结构
Scrapy由以下几部分组成:
- Scrapy Engine:引擎,负责各个部件之间的调度、通信、数据传递等。我的理解是可以理解为一个调用各个程序的操作面板。
- Scheduler:调度器,接收引擎发来的Request请求,按照一定规则进入队列,返回给引擎
- Downloader:下载器,负责下载引擎发送的Request,然后把获取的Response交给引擎,然后引擎交给Spider处理
- Spider:爬虫,定义请求的url等信息,以及对数据的处理
- Item Pipeline:数据管道,爬虫中获取到的数据会放入数据管道,然后在数据管道中进行处理。比如保存到硬盘
此外还有一些中间件,有一些扩展功能
运作流程
- Spider告诉引擎我要做啥,然后引擎安排给Schedule
- Schedule安排发送请求给某网站
- 网站的Response拿到后通过引擎回复给Spider
- Spider把数据处理后放入数据管道
使用步骤
制作一个Scrapy爬虫需要以下几步
- 新建项目(scrapy startproject pj_name):新建一个项目
- 编写items.py:明确需要抓取哪些数据
- 制作Spiders:修改xxspider.py,描述如何获取想要的数据
- 存储内容:修改pipelines.py,设计如何保存数据
安装
在cmd下用如下命令安装
pip install scrapy
在命令行中首先cd到项目保存目录,然后使用scrapy
命令创建名为mydemo
的项目
scrapy startproject demo
cd到mydemo目录,用下面的命令创建名为douban
的蜘蛛程序。
scrapy genspider douban movie.douban.com
例子1:爬取豆瓣电影 Top250 电影标题、评分和金句的爬虫
-
在
items.py
的Item
类中定义字段,这些字段用来保存数据import scrapy class DoubanItem(scrapy.Item): title = scrapy.Field() score = scrapy.Field() motto = scrapy.Field()
-
修改
spiders
文件夹中名为douban.py
的文件,它是蜘蛛程序的核心,需要我们添加解析页面的代码。在这里,我们可以通过对Response
对象的解析,获取电影的信息,代码如下所示。import scrapy from scrapy import Selector, Request from scrapy.http import HtmlResponse from mydemo.items import DoubanItem class DoubanSpider(scrapy.Spider): name = 'douban' allowed_domains = ['movie.douban.com'] def start_requests(self): for page in range(10): yield Request(url=f'https://movie.douban.com/top250?start={page * 25}') def parse(self, response: HtmlResponse): sel = Selector(response) movie_items = sel.css('#content > div > div.article > ol > li') for movie_sel in movie_items: item = DoubanItem() item['title'] = movie_sel.css('.title::text').extract_first() item['score'] = movie_sel.css('.rating_num::text').extract_first() item['motto'] = movie_sel.css('.inq::text').extract_first() yield item
-
将爬取结果保存到Excel中,修改pipelines.py
import openpyxl from mydemo.items import DoubanItem class DoubanItemPipeline: def __init__(self): self.wb = openpyxl.Workbook() self.sheet = self.wb.active self.sheet.title = 'Top250' self.sheet.append(('名称', '评分', '名言')) def process_item(self, item: DoubanItem, spider): self.sheet.append((item['title'], item['score'], item['motto'])) return item def close_spider(self, spider): self.wb.save('output/豆瓣电影数据.xlsx')
-
修改settings.py,主要修改以下几个参数
BOT_NAME = "mydemo" SPIDER_MODULES = ["mydemo.spiders"] NEWSPIDER_MODULE = "mydemo.spiders" # Crawl responsibly by identifying yourself (and your website) on the user-agent USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) " \ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36" # 是否遵守爬虫协议 ROBOTSTXT_OBEY = True # 并发请求数 CONCURRENT_REQUESTS = 8 # 配置数据管道 # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { "mydemo.pipelines.DoubanItemPipeline": 300, }
运行
scrapy crawl douban
实践:爬取Pixiv周榜的标题、作者等信息
-
用如下命令新建spider
scrapy genspider pixiv www.pixiv.net
可以看到在spiders/目录下新建了pixiv.py
-
修改主目录的items.py,添加如下类。这里每个字段就代表了要保存的数据
class PixivItem(scrapy.Item): title = scrapy.Field() user_name = scrapy.Field() p_id = scrapy.Field() re_url = scrapy.Field()
-
修改pixiv.py,注意在custom_settings中指定数据管道
import scrapy from scrapy import Request class PixivSpider(scrapy.Spider): name = "pixiv" allowed_domains = ["www.pixiv.net"] start_urls = ["https://www.pixiv.net"] custom_settings = { 'ITEM_PIPELINES': { # 如果有多条数据管道,需要在这里指定 'mydemo.pipelines.PixivPipeline': 400, } } def start_requests(self): for page in range(1, 6): yield Request(url=f"https://www.pixiv.net/ranking.php?mode=weekly&p={page}&format=json") def parse(self, response, **kwargs): """parse 在 Scrapy 会在 Spider 启动后自动调用,用于处理抓取的网页数据。 """ datas = response.json()["contents"] for data in datas: yield { "title": data["title"], "user_name": data["user_name"], "p_id": data["illust_id"], "re_url": f"https://www.pixiv.net/artworks/{data['illust_id']}" }
-
在主目录的piplines.py中,添加数据管道PixivPipeline
class PixivPipeline: def __init__(self): self.wb = openpyxl.Workbook() self.sheet = self.wb.active self.sheet.title = 'weekly' self.sheet.append(('标题', '作者', 'P_ID', "链接")) def process_item(self, item: PixivItem, spider): self.sheet.append((item['title'], item['user_name'], item['p_id'], item['re_url'])) return item def close_spider(self, spider): # 获取根目录路径 root_path = os.path.abspath(os.path.dirname(__file__)) self.wb.save(f'{root_path}/output/pixiv_weekly_rank数据.xlsx')
-
在settings.py中,添加数据管道
ITEM_PIPELINES = { "mydemo.pipelines.DoubanItemPipeline": 300, "mydemo.pipelines.PixivPipeline": 400 }
运行
scrapy crawl pixiv
完整项目代码地址:
https://github.com/h-kayotin/mydemo