6、scrapy框架基础

爬虫快速入门 / 2021-06-02

一、Scrapy简述

摘自官方文档:

Scrapy is a fast high-level web crawling and web scraping framework, used to crawl websites and extract structured data from their pages. It can be used for a wide range of purposes, from data mining to monitoring and automated testing.

Scrapy是爬虫中的一个明星框架,它具有高性能的持久化存储、异步数据爬取、高性能的数据解析、分布式爬虫的Python爬虫框架!

二、Scrapy基本使用

2.1、环境安装

pip3 install scrapy

2.2、创建Scrapy项目

scrapy startproject tutorial  # 在项目名目录下创建一个爬虫文件,tutorial仅为示例。

创建完后的层级结构应该是这样子的:

tutorial/
    scrapy.cfg            # deploy configuration file

    tutorial/             # project's Python module, you'll import your code from here
        __init__.py

        items.py          # project items definition file

        middlewares.py    # project middlewares file

        pipelines.py      # project pipelines file

        settings.py       # project settings file

        spiders/          # a directory where you'll later put your spiders
            __init__.py

2.3、创建爬虫文件

scrapy genspider example example.com  # 这个域名无关紧要,可以随时更改。

2.4、启动项目

启动爬虫有好几种方式,总的来说是分命令行与脚本文件形式。一个爬虫文件格式如下:

import scrapy


class SpiderSpider(scrapy.Spider):
    name = 'spider'  # 文件名
    allowed_domains = ['baidu.com']  # 允许爬取的URL,不在此范围则不爬取,所以经常会注释掉。
    start_urls = ['http://baidu.com/']  # 爬取的URL列表

    def parse(self, response):  # response为服务器响应内容封装成对象
        print(response.text)  # 获取响应对象的内容
命令行启动
scrapy crawl spider  # crawl后面跟指定的爬虫文件

窗口会打印如下信息:

2021-05-05 10:11:00 [scrapy.core.engine] INFO: Spider opened
2021-05-05 10:11:00 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2021-05-05 10:11:00 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2021-05-05 10:11:00 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (meta refresh) to <GET http://www.baidu.com/> from <GET http://baidu.com/>
2021-05-05 10:11:00 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.baidu.com/> (referer: None)
sanxi666
2021-05-05 10:11:00 [scrapy.core.engine] INFO: Closing spider (finished)
2021-05-05 10:11:00 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 422,
 'downloader/request_count': 2,
 'downloader/request_method_count/GET': 2,
 'downloader/response_bytes': 1838,
 'downloader/response_count': 2,
 'downloader/response_status_count/200': 2,
 'elapsed_time_seconds': 0.249001,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2021, 5, 5, 2, 11, 0, 393058),
 'httpcompression/response_bytes': 2381,
 'httpcompression/response_count': 1,
 'log_count/DEBUG': 2,
 'log_count/INFO': 10,
 'response_received_count': 1,
 'scheduler/dequeued': 2,
 'scheduler/dequeued/memory': 2,
 'scheduler/enqueued': 2,
 'scheduler/enqueued/memory': 2,
 'start_time': datetime.datetime(2021, 5, 5, 2, 11, 0, 144057)}
2021-05-05 10:11:00 [scrapy.core.engine] INFO: Spider closed (finished)
脚本文件启动
import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
from twisted.internet import reactor


class SpiderSpider(scrapy.Spider):
    name = 'spider'
    allowed_domains = ['baidu.com']
    start_urls = ['http://baidu.com/']

    def parse(self, response):
        print('sanxi666')


configure_logging()  # 打印爬取日志
runner = CrawlerRunner()  # 实例化runner对象
runner.crawl(SpiderSpider)  # 爬取指定的类或文件中所定义的爬虫方法
# runner.crawl(SpiderSpider2)  # 如果有多个爬虫方法就这样定义即可
do = runner.join()  # 等待所有爬虫程序结束
do.addBoth(lambda _: reactor.stop())  # 停止

reactor.run()
常用settings配置

跟Django类似

ROBOTSTXT_OBEY = False  # 不遵循robots协议# UA伪装USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 '  'Safari/537.36 'DOWNLOAD_DELAY = 3  # 下载失败的重试次数LOG_LEVEL = 'ERROR'  # 输出的日志等级

三、Scrapy数据解析

Scrapy毋须获取响应对象,直接用response.xpath()解析数据,用法跟lxml的xpath基本一样的,返回也是列表。

extract(),将selector对象中data参数存储的所有文本提取出来,extract_first取第一个,返回的也是列表形式。

class SpiderSpider(scrapy.Spider):    name = 'spider'    # allowed_domains = ['baidu.com']    start_urls = ['https://docs.djangoproject.com/zh-hans/2.2/']    def parse(self, response):        ui_list = response.xpath('//*[@id="s-the-view-layer"]/ul')  # 用xpath解析响应内容        for ui in ui_list:            ui_content = ui.xpath('./li/strong/text()')[0].extract()  # extract()获取data里面的文本信息

未完待续。。。其实是我不想写了

Scrapy持久化存储

有两种方式,一种基本命令行,另一种是基于管道传输。

基于终端指令

直接在命令行启动爬虫时指定输出文件格式,此方法仅可将parse方法的返回值存储到本地的文本文件中

-o 跟一个文件,仅支持json、xml、CSV等

优点:简捷

缺点:不够灵活,只能是规定的格式,不能存储在数据库

基于管道

流程:

数据解析

item类定义相关属性

将结果封装存储到item类型的对象中

image-20210501225637490

将item对象提交给管道进行持久化存储

爬虫提交的item只会给管道第一个类接受,所以第一个管道类应该return一个item对象

在pipelines中,用process_item来处理item对象,每接受一个item就会调用一次

重写父类的open_spider()方法,仅在爬虫开始时调用一次,在这里打开文件写入即可

重写close_spider(),结束时调用一次,可以在这里关闭文件

配置文件开启管道

ITEM_PIPELINES

image-20210501230239516

优点:

兼容性强,可存储在多种渠道

缺点:

需要注意编码

通过管道存储到数据库

image-20210502110252083

基于spider的全站数据爬取

即将网站某个板块下的全部页码对应的页面数据进行爬取

实现方式:

将所有页面的URL添加到start_urls列表中,但是不推荐

手动进行请求发送

image-20210502112958987

五大核心组件:

请求传参:

使用场景:如果爬取解析的数据不在同一张页面,这需要深度爬取

爬取boss直聘岗位

请求传参,传的是item对象,使用meta={},可以将meta字典传给请求回应的回调函数

回调函数接受item

使用response.meta['item']

世间微尘里 独爱茶酒中