概述
本文记录了个人使用 Scrapy 爬取某网站产品信息(包含图片下载)的整个过程,也可以作为一篇 Scrapy 实战教学博客。 首先从 All Products 页面出发,首先抓取所有分类页面的链接:如 https://www.example.com/category/category-name 再从每个产品分类页面抓取产品详情页面链接:如 https://www.example.com/product/product-name 最后解析产品详情页面的响应,提取所需数据,下载相关图片
开始
首先需要安装 scrapy,pip命令
pip install scrapy
启动项目
在 Pycharm 工作目录下新建一个名为 scrapy_demo 的目录(以后其他scrapy 爬虫项目也可以放到该目录下),打开终端 Terminal,使用 cd 命令进入 scrapy_demo 目录,使用 scrapy 创建项目命令:
scrapy startproject product
其中 product 是爬虫项目名,可以修改 此时目录结构应该如下:(products_spider.py 是后面自己添加的) 各目录结构详解请参考官方文档
爬虫初始化
- 在 spiders 目录下新建一个 products_spider.py 文件(命名似乎并无严格要求)
- 加入初始代码:
import scrapy
from ..items import ProductItem
class ProductsSpider(scrapy.Spider):
"""
Products Spider
"""
name = "products"
host = 'http://www.example.com'
def start_requests(self):
urls = [
'http://www.example.com/products.html'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response, **kwargs):
pass
爬虫执行的流程:首先会执行 start_requests 方法,最后 yield Request 发出多个请求,请求的响应将会被 Request 中的参数 callback 所指定的函数接收并处理,这里对首页的请求的响应将会被 parse 函数处理。
- 定义 Item,也就是需要获取的字段,在 items.py 中编写代码。示例如下:
import scrapy
class ProductItem(scrapy.Item):
name = scrapy.Field()
images = scrapy.Field()
category = scrapy.Field()
price = scrapy.Field()
description = scrapy.Field()
pass
处理响应
回到 products_spider.py 中,接下来需要对响应进行处理。
- 在函数 parse 中的 response 是首页的响应,我们需要从中获取到每一个分类页面的链接,(解析数据个人用的是 xpath)然后对每一个链接再发起请求,并把响应交给处理分类页面的响应的函数。
- 因此,额外再编写一个函数 parse_category 用于处理分类页面的响应。
- 同理,分类页面获取到产品详情页面的链接,再次发起请求,并将响应交给 parse_product 函数。
- 代码如下:
def parse(self, response, **kwargs):
tree = etree.HTML(response.text)
hrefs = tree.xpath("hrefs xpath express")
for href in hrefs:
yield scrapy.Request(url=self.host + href, callback=self.parse_category)
def parse_category(self, response):
tree = etree.HTML(response.text)
product_urls = tree.xpath("products url xpath express")
category = tree.xpath("categroy text xpath express")[0]
for url in product_urls:
yield scrapy.Request(url=self.host + url, callback=self.parse_product)
def parse_product(self, response):
tree = etree.HTML(response.text)
item = ProductItem()
item['name'] = tree.xpath('xxxxx/text()')[0]
yield item
回调函数的参数
- 当我们在 parse_product 函数中想获取产品分类填充到 item 中,而产品详情页面中没有该数据,产品分类数据在分类页面中。要怎么做呢?
- 这种情况需要在 parse_category 函数中获取产品分类,并将该产品分类数据传递到函数 parse_product 函数中。实际上,这里的一些列 parse_* 函数都可以称为回调,那么我们要如何传递参数给回调函数呢?
- 详细请参考官方文档,我这里直接给出代码:在 yield Request 时,可以添加一个额外参数:cb_kwargs={‘cate’: category},它的值是一个字典,表示将 category 的值传递给下一个响应处理函数,即 parse_product ,同时在 parse_product 中添加一个名为 cate 的参数来接收值
def parse_category(self, response):
yield scrapy.Request(url=self.host + url, callback=self.parse_product, cb_kwargs={'cate': category})
pass
def parse_product(self, response, cate):
item['category'] = cate
图片下载(未完待续)
使用中间件 ImagesPipeline
相关资源
官方文档:点击跳转
|