diff --git a/FormalSciences/ComputerScience/ProgrammingLanguage/Python/3.Libraires/网络爬虫与数据抓取/Scrapy.md b/FormalSciences/ComputerScience/ProgrammingLanguage/Python/3.Libraires/网络爬虫与数据抓取/Scrapy.md index ca5b6a23..e4938f9f 100644 --- a/FormalSciences/ComputerScience/ProgrammingLanguage/Python/3.Libraires/网络爬虫与数据抓取/Scrapy.md +++ b/FormalSciences/ComputerScience/ProgrammingLanguage/Python/3.Libraires/网络爬虫与数据抓取/Scrapy.md @@ -1469,3 +1469,323 @@ Scrapy 项目的配置文件(`settings.py`)集中管理了所有与爬虫行 from .settings_base import * DOWNLOAD_DELAY = 0.5 ``` + +## 实战案例分析 + +通过实际项目的分析与实践,可以更好地理解如何将 Scrapy 用于解决现实中的数据抓取问题。本节将通过电商网站的数据采集示例,展示如何进行爬虫设计、数据存储及分析。 + +### 电商网站数据采集 + +电商网站上通常包含产品名称、价格、库存、评价等关键信息,这些数据对市场分析、竞品研究有重要的参考价值。我们将以模拟电商网站为例,展示如何通过 Scrapy 实现数据采集,并将其存储与分析。 + +#### 项目需求与目标 + +**需求与目标:** + +- 抓取某电商网站的产品信息,包括产品名称、价格、库存、评价数、产品详情页链接等。 +- 实现定期抓取,分析产品价格变化趋势,并进行竞品比价。 +- 需要将数据存储到数据库或导出为 CSV 文件,以便后续数据分析和可视化。 + +**具体数据抓取字段:** + +- 产品名称(name) +- 价格(price) +- 库存(stock) +- 评价数(reviews) +- 产品详情页链接(url) + +#### **爬虫设计与实现** + +**目标网站:** 我们以模拟的电商网站 http://books.toscrape.com/ 为例,这是一个包含书籍商品信息的示例网站,页面包含产品名称、价格、库存等信息,非常适合做数据抓取示例。 + +1. **创建 Scrapy 项目**:首先,我们创建一个 Scrapy 项目,用于抓取数据: + + ```shell + scrapy startproject ecommerce_spider + ``` + +2. **生成 Spider:**在生成的项目中,使用 `scrapy genspider` 命令来创建一个名为 `book_spider` 的爬虫: + + ```shell + scrapy genspider book_spider books.toscrape.com + ``` + +3. **编写 Spider**: 创建 Spider 并定义数据抓取逻辑。我们将抓取书籍的名称、价格、库存、评价数等信息。 + + ```python + import scrapy + + class BookSpider(scrapy.Spider): + name = 'book_spider' + start_urls = ['http://books.toscrape.com/'] + + def parse(self, response): + # 解析每本书的信息 + for book in response.css('article.product_pod'): + yield { + 'name': book.css('h3 a::attr(title)').get(), + 'price': book.css('div.product_price p.price_color::text').get(), + 'stock': book.css('p.instock.availability::text').re_first('\d+'), + 'reviews': book.css('p.star-rating::attr(class)').re_first('star-rating (\w+)'), + 'url': response.urljoin(book.css('h3 a::attr(href)').get()), # 完整的 URL + } + + # 处理分页 + next_page = response.css('li.next a::attr(href)').get() + if next_page: + yield response.follow(next_page, self.parse) + ``` + +**解释:** + +- 我们通过 CSS 选择器提取需要的信息,如书名、价格、库存情况、星级评测等。 +- `response.urljoin()` 用于生成书籍详情页的完整链接。 +- 分页处理:如果存在“下一页”,通过 `response.follow()` 方法继续抓取下一页的内容。 + +1. **运行爬虫并保存数据**: 通过以下命令运行爬虫并将数据保存到 CSV 文件中: + +```shell +scrapy crawl book_spider -o books.csv +``` + +爬虫会自动抓取整个网站的书籍数据并保存为 CSV 文件,便于后续的数据分析。 + +#### 数据存储与分析 + +爬取的数据可以存储到 CSV 文件、数据库(如 MySQL、MongoDB)或其他格式中。这里我们将数据保存到 MySQL 数据库中。 + +**将数据存储到 MySQL**: + +1. 安装 MySQL 依赖: + + ```shell + pip install pymysql + ``` + +2. 在 Scrapy 中定义数据管道,将抓取的数据保存到数据库中。 + + ```python + import pymysql + import re + + class MySQLPipeline: + def open_spider(self, spider): + self.connection = pymysql.connect( + host='localhost', + user='root', + password='password', # 修改为您的数据库密码 + db='ecommerce_db', # 请确保数据库已存在 + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor + ) + self.cursor = self.connection.cursor() + + def close_spider(self, spider): + self.connection.close() + + def process_item(self, item, spider): + # 清洗价格字段,移除货币符号并转换为浮点数 + if 'price' in item: + item['price'] = re.sub(r'[^\d.]', '', item['price']) # 移除非数字字符(如£) + item['price'] = float(item['price']) if item['price'] else 0.0 + + # 插入到 MySQL 数据库 + sql = """ + INSERT INTO products (name, price, stock, reviews, url) + VALUES (%s, %s, %s, %s, %s) + """ + + # 为了处理库存的空值,确保 stock 是整数类型 + stock = item.get('stock') + if stock is None: + stock = 0 + + # 插入数据 + self.cursor.execute(sql, ( + item['name'], + item['price'], + stock, + item['reviews'], + item['url'] + )) + self.connection.commit() + return item + ``` + +3. **启用 Pipeline**: + + 在 `settings.py` 中启用 MySQL Pipeline: + + ```python + ITEM_PIPELINES = { + 'ecommerce_spider.pipelines.MySQLPipeline': 300, + } + ``` + +4. 创建 MySQL 数据库和表。 + + ```mysql + CREATE DATABASE ecommerce_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + + USE ecommerce_db; + + CREATE TABLE products ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + price DECIMAL(10, 2) NOT NULL, + stock INT DEFAULT 0, + reviews VARCHAR(50), + url VARCHAR(2083) + ); + ``` + +5. **运行爬虫并保存数据**: 通过以下命令运行爬虫并将数据保存到数据库中,爬虫会自动抓取整个网站的书籍数据并保存到数据库,便于后续的数据分析。 + + ```shell + scrapy crawl book_spider + ``` + +6. 接下来,我们使用 Pandas 对数据进行分析,并使用 Matplotlib 进行可视化。 + + ```shell + # 安装依赖 + pip install pandas matplotlib sqlalchemy + ``` + + ```python + # 分析价格变化趋 + import pandas as pd + import matplotlib.pyplot as plt + from sqlalchemy import create_engine + + # 创建数据库连接 + engine = create_engine('mysql+pymysql://root:password@localhost/ecommerce_db') + + # 读取数据到 DataFrame + df = pd.read_sql('SELECT * FROM products', con=engine) + + # 进行价格分析和可视化 + print(df['price'].describe()) + + # 可视化价格分布 + df['price'].hist(bins=20) + plt.xlabel('Price (£)') + plt.ylabel('Number of Books') + plt.title('Price Distribution of Books') + plt.grid(axis='y') + plt.show() + ``` + + 通过 Pandas 可以轻松实现数据的统计、清洗和可视化,后续可以进一步进行竞品分析或趋势预测。 + +### 社交媒体数据抓取 + +社交媒体平台提供了大量实时数据,包括用户发布的动态、评论、点赞等,这些数据可以用于舆情监控、市场分析、广告效果评估等。然而,社交媒体通常会有较强的反爬机制,需要采用特殊的策略。 + +#### 反爬策略的应对 + +社交媒体网站通常采用如下反爬策略: + +- **频繁的 IP 封禁**:检测过高的请求频率并封禁 IP。 +- **强制登录**:很多内容只能登录后访问。 +- **动态加载**:许多数据通过 JavaScript 加载或 AJAX 请求动态更新。 + +**应对策略:** + +- **使用代理 IP 池**:通过不断切换 IP 来分散请求。 +- **模拟登录与会话保持**:使用 Selenium 或 Scrapy 的 `FormRequest` 模拟登录并保持会话。 +- **处理动态加载**:可以使用 Selenium 或 Splash 处理 JavaScript 渲染。 + +#### 实时数据的抓取与更新 + +社交媒体数据通常是动态、实时更新的,因此需要定期抓取并更新数据。 + +```python +# 实时抓取推特上的特定关键词(示例) +import scrapy +from scrapy_selenium import SeleniumRequest + +class TwitterSpider(scrapy.Spider): + name = 'twitter_spider' + start_urls = ['https://twitter.com/search?q=python&src=typed_query'] + + def start_requests(self): + for url in self.start_urls: + yield SeleniumRequest(url=url, callback=self.parse) + + def parse(self, response): + tweets = response.css('div.css-901oao') + for tweet in tweets: + yield { + 'user': tweet.css('span.username::text').get(), + 'content': tweet.css('div.tweet-text::text').get(), + 'time': tweet.css('a.tweet-timestamp::attr(title)').get(), + } +``` + +通过 Scrapy-Selenium 集成,可以处理 Twitter 页面上的 JavaScript 渲染并抓取最新的推文。 + +### 新闻资讯聚合爬虫 + +新闻聚合爬虫用于从多个新闻源抓取信息,并将不同来源的新闻汇总处理。由于不同网站的结构差异较大,爬虫需要具备处理多源异构数据的能力。 + +#### 多源异构数据的处理 + +当抓取来自不同新闻源的数据时,页面结构往往各异。因此,我们需要为不同的网站编写相应的解析逻辑,同时保证抓取的数据结构统一。 + +```python +class NewsSpider1(scrapy.Spider): + name = 'news_spider_1' + start_urls = ['http://example-news-site1.com'] + + def parse(self, response): + for article in response.css('div.article'): + yield { + 'title': article.css('h1::text').get(), + 'content': article.css('div.content::text').get(), + 'source': 'Site1' + } + +class NewsSpider2(scrapy.Spider): + name = 'news_spider_2' + start_urls = ['http://example-news-site2.com'] + + def parse(self, response): + for article in response.css('div.news'): + yield { + 'title': article.css('h2::text').get(), + 'content': article.css('p.summary::text').get(), + 'source': 'Site2' + } +``` + +通过编写不同的爬虫来处理不同新闻网站的页面结构,但最终输出的数据格式是统一的。 + +#### 数据清洗与内容分析 + +抓取到的新闻数据可能包含广告、无关内容或重复信息,因此需要进行数据清洗。可以使用正则表达式、关键词过滤等方法去除无关数据,并通过自然语言处理技术进行内容分析。 + +```python +# 清洗新闻数据并进行关键词提取 +import re +from collections import Counter +import pandas as pd + +def clean_text(text): + text = re.sub(r'\s+', ' ', text) # 去除多余空白 + text = re.sub(r'[^\w\s]', '', text) # 去除标点符号 + return text.lower() + +# 加载数据 +df = pd.read_csv('news.csv') + +# 清洗数据 +df['cleaned_content'] = df['content'].apply(clean_text) + +# 提取关键词 +all_words = ' '.join(df['cleaned_content']).split() +word_freq = Counter(all_words) +print(word_freq.most_common(10)) +``` + +通过数据清洗和分析,可以提取出新闻中的关键趋势和话题。