Python爬虫案例:Scrapy+XPath解析当当网网页结构
引言
在当今大数据时代,网络爬虫已成为获取互联网信息的重要工具。作为Python生态中最强大的爬虫框架之一,Scrapy凭借其高性能、易扩展的特性受到开发者广泛青睐。本文将详细介绍如何利用Scrapy框架结合XPath技术解析当当网的商品页面结构,实现一个完整的电商数据爬取案例。
一、Scrapy框架概述
Scrapy是一个为了爬取网站数据、提取结构性数据而编写的应用框架,可以广泛应用于数据挖掘、监测和自动化测试等地方。其架构设计基于Twisted异步网络框架,具有以下核心组件:
- 引擎(Engine): 控制数据流在系统中的所有组件流动
- 调度器(Scheduler): 从引擎接收请求并排队
- 下载器(Downloader): 获取网页并返回给爬虫
- 爬虫(Spiders): 用户编写的解析响应和提取数据的类
- 项目管道(Item Pipeline): 处理被爬虫提取出来的项目
二、项目环境搭建
在开始之前,我们需要安装必要的Python库
创建Scrapy项目:
三、当当网页面结构分析
在编写爬虫之前,我们需要先分析当当网的页面结构。以图书商品页为例(如:http://product.dangdang.com/29116046.html),主要包含以下信息:%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%8C%85%E5%90%AB%E4%BB%A5%E4%B8%8B%E4%BF%A1%E6%81%AF%EF%BC%9A)
- 商品标题
- 商品价格
- 作者信息
- 出版社信息
- 出版时间
- 商品详情
- 用户评价
使用浏览器开发者工具(F12)可以查看页面HTML结构,为后续XPath编写做准备。
四、定义数据模型
在**items.py**
中定义我们要抓取的数据字段:
import scrapyclass DangdangItem(scrapy.Item): title = scrapy.Field() # 商品标题 price = scrapy.Field() # 商品价格 author = scrapy.Field() # 作者 publisher = scrapy.Field() # 出版社 publish_date = scrapy.Field() # 出版日期 detail = scrapy.Field() # 商品详情 comments = scrapy.Field() # 用户评价数量 isbn = scrapy.Field() # ISBN号 url = scrapy.Field() # 商品链接
五、编写爬虫核心代码
在**spiders/dd_spider.py**
中编写爬虫逻辑:
import scrapyfrom dangdang.items import DangdangItemfrom scrapy.http import Requestclass DdSpiderSpider(scrapy.Spider): name = \'dd_spider\' allowed_domains = [\'dangdang.com\'] start_urls = [\'http://category.dangdang.com/cp01.54.06.00.00.00.html\'] # 从图书分类页开始 # 解析分类页,获取商品详情页链接 def parse(self, response): book_links = response.xpath(\'//a[@name=\"itemlist-picture\"]/@href\').extract() for link in book_links: yield Request(url=link, callback=self.parse_book) # 处理分页 next_page = response.xpath(\'//li[@class=\"next\"]/a/@href\').extract_first() if next_page: yield Request(url=next_page, callback=self.parse) # 解析商品详情页 def parse_book(self, response): item = DangdangItem() # 使用XPath提取数据 item[\'title\'] = response.xpath(\'//div[@class=\"name_info\"]/h1/@title\').extract_first() item[\'price\'] = response.xpath(\'//p[@id=\"dd-price\"]/text()\').extract_first().strip() # 作者信息可能有多人 authors = response.xpath(\'//span[@id=\"author\"]/a/text()\').extract() item[\'author\'] = \' \'.join(authors) if authors else None item[\'publisher\'] = response.xpath(\'//a[@dd_name=\"出版社\"]/text()\').extract_first() item[\'publish_date\'] = response.xpath(\'//div[@class=\"messbox_info\"]/span[2]/text()\').extract_first() # 处理详情信息 details = [] detail_nodes = response.xpath(\'//div[@class=\"detail_content\"]//text()\').extract() for detail in detail_nodes: if detail.strip(): details.append(detail.strip()) item[\'detail\'] = \'\\n\'.join(details) item[\'comments\'] = response.xpath(\'//a[@dd_name=\"单品页点击评论\"]/text()\').extract_first() item[\'isbn\'] = response.xpath(\'//div[@class=\"messbox_info\"]/span[last()]/text()\').extract_first() item[\'url\'] = response.url yield item
六、XPath选择器详解
XPath是一种在XML文档中查找信息的语言,同样适用于HTML文档。上述代码中我们使用了多种XPath表达式:
**//a[@name=\"itemlist-picture\"]/@href**
- 选择所有name属性为\"itemlist-picture\"的a标签的href属性**//div[@class=\"name_info\"]/h1/@title**
- 选择class为\"name_info\"的div下的h1标签的title属性**//span[@id=\"author\"]/a/text()**
- 选择id为\"author\"的span下的所有a标签的文本**//div[@class=\"messbox_info\"]/span[2]/text()**
- 选择class为\"messbox_info\"的div下的第二个span标签的文本
XPath选择器比正则表达式更直观,更适合处理HTML文档的层次结构。
七、处理反爬机制
当当网和其他电商网站一样,都有反爬虫机制。我们需要在**settings.py**
中进行一些配置:
python
# 代理配置PROXY_HOST = \"www.16yun.cn\"PROXY_PORT = \"5445\"PROXY_USER = \"16QMSOML\"PROXY_PASS = \"280651\"# 设置下载延迟DOWNLOAD_DELAY = 2# 启用AutoThrottle扩展AUTOTHROTTLE_ENABLED = TrueAUTOTHROTTLE_START_DELAY = 5AUTOTHROTTLE_MAX_DELAY = 60# 设置User-AgentUSER_AGENT = \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\'# 启用CookiesCOOKIES_ENABLED = True# 配置中间件DOWNLOADER_MIDDLEWARES = { \'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware\': None, \'scrapy_user_agents.middlewares.RandomUserAgentMiddleware\': 400, \'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware\': 100, \'dangdang.middlewares.ProxyMiddleware\': 110, # 自定义代理中间件}
八、数据存储处理
在**pipelines.py**
中实现数据存储逻辑,这里以MongoDB为例:
python
import pymongoclass MongoDBPipeline(object): def __init__(self, mongo_uri, mongo_db): self.mongo_uri = mongo_uri self.mongo_db = mongo_db @classmethod def from_crawler(cls, crawler): return cls( mongo_uri=crawler.settings.get(\'MONGO_URI\'), mongo_db=crawler.settings.get(\'MONGO_DATABASE\', \'dangdang\') ) def open_spider(self, spider): self.client = pymongo.MongoClient(self.mongo_uri) self.db = self.client[self.mongo_db] def close_spider(self, spider): self.client.close() def process_item(self, item, spider): collection_name = item.__class__.__name__ self.db[collection_name].insert_one(dict(item)) return item
在**settings.py**
中启用管道并配置MongoDB连接:
python
ITEM_PIPELINES = { \'dangdang.pipelines.MongoDBPipeline\': 300,}MONGO_URI = \'mongodb://localhost:27017\'MONGO_DATABASE = \'dangdang\'
九、高级技巧与优化
- 分布式爬取:使用Scrapy-Redis实现分布式爬虫
- 动态内容处理:对于JavaScript渲染的内容,可以使用Splash或Selenium中间件
- 增量爬取:通过记录已爬取的URL实现增量爬取
- 异常处理:增强爬虫的健壮性
结语
本文详细介绍了使用Scrapy框架和XPath技术爬取当当网商品信息的全过程。通过这个案例,我们学习了如何分析网页结构、编写XPath选择器、处理反爬机制以及存储爬取结果。Scrapy的强大功能结合XPath的灵活选择能力,可以应对大多数网页爬取需求。