scrapy(1)

Scrapy框架架构

框架介绍

写一个爬虫,我们需要发送网络请求、数据分析、数据存储、反反爬虫机制(更换ip代理,设置请求头等),异步请求等。scrapy把这些基础的东西都已经写好了,可以提高爬虫的爬取效率与开发效率。

Scrapy架构图


  • 1.spider(爬虫)给scheduler(调度器)发送请求
  • 2.scheduler接收请求,将其存储在自己的队列中
  • 3.引擎(engine)不断地向scheduler提取请求
  • 4.engine将请求给downloader(下载器),下载器到互联网上下载资源
  • 5.engine接收到downloader返回的响应
  • 6.engine将响应返回给spider
  • 7.spider进行数据的分析与提取,将提取后的数据送给engine
  • 8.engine将提取后的数据送给pipeline,指定数据存储方式

模块功能

  1. Spider Engine(引擎):Scrapy的核心部分,负责在其他模块中间通信
  2. Spider(爬虫):发生需要爬取的链接给引擎,最后引擎把其他模块响应的数据返回给爬虫,由爬虫对数据进行分析提取,由开发者自行决定
  3. Scheduler(调度器):负责接收引擎发送过来的请求,并按照一定方式排列整理,负责调度请求的顺序
  4. Downloader(下载器):负责接收引擎传过来的下载请求,然后去下载对应的数据再交还给引擎
  5. Item Pipeline(管道):负责存储爬虫传递的数据,由开发者决定数据存储位置
  6. Downloader Middlewares(下载中间件):可以扩展下载器和引擎之间通信功能的中间件
  7. Spider Middlewares(Spider中间件):可以扩展爬虫和引擎之间通信功能的中间件

安装scrapy

  1. 在windows下安装scrapy,首先要保证已经安装python环境
  2. 安装anaconda
  3. 在开始的地方找到Anaconda Prompt运行,输入以下指令:
    conda install scrapy   #安装
    scrapy   #检测是否安装成功

创建scrapy项目

先自己新建一个文件夹用来放scrapy项目,打开anaconda环境,即上面提及的Anaconda Prompt,使用命令行进入该文件夹。

项目结构

使用Pycharm打开项目文件夹

创建爬虫

在Anaconda Prompt下进入刚刚创建的目录下,新建爬虫

scrapy genspider 爬虫名 "爬取的域名"
scrapy genspider xixi "cr137.com"

上述命令创建成功后会在init.py下多一个xixi.py,该文件是爬虫的main文件

设置settings文件


设置请求头,伪装身份,必要时设置DOWNLOAD_DELAY。如果要存储数据要将此文件中pipelines的注释去掉

init.py文件

打开新建的xixi.py文件,parse()函数是用于接收scrapy爬虫架构第6步返回的响应

运行爬虫

在Anaconda Prompt中执行以下命令即可执行爬虫

scrapy crawl 爬虫名

查看响应类型可采用的方法

查看响应的类型,xixi.py:

def parse(self,response):
    print('='*40)
    print(type(response))
    print('='*40)

在xixi.py里加入以下语句:

from scrapy.http.response.html import HtmlResponse

查看方法的方式是鼠标选中要查看的类,按下ctrl+b(或长按ctrl用鼠标点击类名),在上述例子中我们想查看HtmlResponse的方法,鼠标选中HtmlResponse,按下ctrl+b,得到下图

由上图可知HtmlResponse继承自TextResponse类,继续查看TextResponse类的方法

快捷执行方式

在爬虫项目下新建一个python文件start.py,写入以下代码:

from scrapy import cmdline
cmdline.execute("scrapy crawl xixi".split())

执行此文件即可开始爬虫,就不需要再打开Anaconda Prompt

CrawlSpider

CrawlSpider继承自Spider,只不过比Spider多了可以定义爬取的url的规则,以后scrapy碰到满足条件的url都进行爬取,而不用手动的yield Request.

创建CrawlSpider爬虫

通过以下命令在Anaconda Prompt里创建CrawlSpider:

scrapy genspider -t crawl [爬虫名] [域名]

LinkExtractors链接提取器

可以在所有爬的页面中找到满足规则的url,实现自动的爬取。

class scrapy.linkextractors.LinkExtractor{
    allow = (),
    deny = (),
    allow_domains = (),
    deny_domains = (),
    restrict_xpaths = (),
    tags = ('a','area'),
    attrs = ('href'),
    canonicalize = True,
    unique = True,
    process_value = None
}

主要参数:

  • allow:允许的url,所有满足这个正则表达式的url都会被提取。
  • deny:禁止的url,所有满足这个正则表达式的url都不会被提取
  • allow_domain:允许的域名,只有在这个里面指定的域名的url才会被提取
  • deny_domain:禁止的域名,所有在这个里面指定的域名的url都不会被提取
  • restrict_xpaths:严格的xpaths,和allow共同的过滤链接

Rule规则类

定义爬虫的规则类:

class scrapy.spider.Rule{
    link_extractors,
    callback = None,
    cb_kwargs = None,
    follow = None,
    process_links = None,
    process_request = None
}

主要参数:

  • link_extractor:一个LinkExtractor对象,用于定义爬取规则。
  • callback:满足这个规则的Url,应该执行哪个回调函数。因为CrawlSpider使用了parse作为回调函数,因此不要覆盖parse作为回调函数自己的回调函数
  • follow:指定根据该规则从response提取的链接是否需要跟进
  • process_links:从link_extractor中获取到链接后会传递给这个函数,用来过滤不需要爬取的链接。

CrawlSpider实战

创建CrawlSpider项目,在项目下创建爬虫文件wxapp.py,打开微信小程序社区的教程部分,找规律

  1. 点击不同的页数的页面,观察url变化


    发现只有page参数变化

  2. 点击不同的文章进行查看

配置准备

设置setting文件,新建文件start.py执行爬虫,运行即可

页面爬取

在wxapp.py文件里修改rules,对爬取信息进行筛选,如上面的url爬取。

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class WxSpider(CrawlSpider):
    name = 'wx'
    allowed_domains = ['wxapp-union.com']
    start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1']
    #翻页
    rules = (
        Rule(LinkExtractor(allow=r'.+mod=list&catid=2&page=\d'),
              follow=True),    #此处不需要指定回调,自动爬取即可
        #进一步解析相同域名,即进一步爬取每篇文章的详细内容
    )
    #点击查看具体页面
        Rule(LinkExtractor(allow=r'.+article-.+\.html'),
            callback="parse_item",follow=False) #不需要跟进,不用再继续解析

    def parse_item(self, response):
        title = response.xpath("//h1[@class='ph']/text()").get()
        print(title)

提取作者时间

wx.py:

 def parse_item(self, response):
        author_p = response.xpath(".//p[@class='authors']")    #返回响应这个对象,类型为object
        author = author_p.xpath(".//a/text()").get()  #get()返回响应内容,类型为字符串  .//表示在当前环境
        time = author_p.xpath(".//span/text()").get()
        print("author:%s / time:%s" % (author,time))
        print("="*40)

提取前言部分


wx.py

 def parse_item(self, response):
        text_p = response.xpath("//div[@class='blockquote']")
        text = text_p.xpath(".//p/text()").get()
        print(text)
        print("="*40)

存储以上提取的所有信息

items.py

#用来描述自定义数据包含哪些字段信息
class WxappItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    time = scrapy.Field()
    text = scrapy.Field()

pipeline.py

from scrapy.exporters import JsonLinesItemExporter  #JsonLinesExporter将数据直接存到硬盘中,而不需要存在内存中
class WxappPipeline(object):
    def __init__(self):
        self.fp = open("wx.json",'wb')
        self.exporter = JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')
    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item
    #关闭爬虫
    def close_spider(self,spider):
        self.fp.close()

wx.py

 def parse_item(self, response):
        title = response.xpath("//h1[@class='ph']/text()").get()
        author_p = response.xpath(".//p[@class='authors']")  # 返回响应这个对象,类型为object
        author = author_p.xpath(".//a/text()").get()  # get()返回响应内容,类型为字符串
        time = author_p.xpath(".//span/text()").get()
        text_p = response.xpath("//div[@class='blockquote']")
        text = text_p.xpath(".//p/text()").get()
        item = WxappItem(title=title,author=author,time=time,text=text)
        return item

在同等文件夹下创建新文件

os_path.py

import os
path = os.path.join(os.path.dirname(os.path.dirname(__file__)),'文件夹名')  #在该文件的相同文件夹下新建一个文件 os.path.dirname表示上一级目录
if not os.path.exists(path):
    os.mkdir(path)
else:
    print("文件夹存在")

   转载规则


《scrapy(1)》 fightingtree 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录