scrapy框架基础

scrapy框架基础

一、Scrapy Shell

1.简介

Scrapy Shell是用来调试Scrapy项目代码的命令行工具,启动的时候预定义了Scrapy的一些对象

Scrapy Shell的作用:调试

2.设置

Scrapy 的shell是基于运行环境中的python 解释器shell,本质上就是通过命令调用shell,并在启动的时候预定义需要使用的对象

scrapy允许通过在项目配置文件”scrapy.cfg”中进行配置来指定解释器shell

# scrapy.cfg
[settings]
shell = ipython

注意:如果安装了ipython且没有指定解释器shell,会默认使用ipython

3.启动

启动Scrapy shell的命令

scrapy shell [url|file]

url 就是你想要爬取的网址,file是本地文件

注意:分析本地文件是一定要带上路径,scrapy shell会默认当作url

4.使用

[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x00000203907D6BA8>
[s]   item       {}
[s]   settings   <scrapy.settings.Settings object at 0x00000203907D6978>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser

二、Selector

1.简介

scrapy提供了自己的数据提取方法,即selector(选择器)。selector是基于lxml来构建的,支持XPath选择器、CSS选择器以及正则表达式

response有一个属性selector,调用response.selector返回的内容相当于用text构造了一个Selector对象,进而调用以下方法,返回的结果是Selector组成的列表,是SelectorList类型,SelectorList类型可以继续调用以下方法,另外传入的response可以直接调用xpath()和css()方法

2.extract()

  • .extract():序列化该节点为Unicode字符串并返回list列表

  • .extract_first():序列化该节点为Unicode字符串并返回list列表的第一个值,列表为空时返回为空,不会报错,另外可设置默认值参数,列表为空时返回该参数,例如.extract_first("no value"),当列表为空时返回'no value'

3.xpath()

  • .xpath(query):传入XPath表达式query,返回该表达式所对应的所有节点的SelectorList列表

4.css()

  • .css(query):传入css表达式query,返回该表达式所对应的所有节点的SelectorList列表

5.正则表达式

  • .re(regex):根据传入的正则表达式对数据进行提取,返回Unicode字符串列表

  • .re_first(regex):根据传入的正则表达式对数据进行提取,返回Unicode字符串列表的第一个值

注意:response对象不能直接调用re()、re_first()方法,可以先调用xpath()方法再正则匹配:response.xpath('.').re(regex)

三、Spider

1.简介

实现Scrapy爬虫项目最核心的类是Spider类,它定义爬取网站的动作、分析爬取下来的网页

2.Spider运行流程

以初始URL初始化Request,并设置回调函数,当该Request请求成功并返回Response作为参数传给该回调函数,在回调函数中解析Response,一是得到有效结果返回字典或Item对象,二是解析出下一个网页链接,利用其构造Request并设置新的回调函数

3.Spider类分析

scrapy.Spider类是其他spider类的基类,所有spider类都必须继承scrapy.Spider类

scrapy.Spider类提供了start_requests()方法的默认实现,读取并请求start_urls属性,并根据返回的Response调用parse()方法

4.Spider类的常用属性

  • name:爬虫名称,定义Spider名字的字符串,Spider最重要的属性。Scrapy使用name来定位和初始化Spider,因此它必须是唯一的,name一般使用爬取网站的域名
  • allowed_domains:允许爬取的域名列表。可选配置,不在此范围的链接不会被跟进爬取
  • start_urls:起始的URL列表。没有重写start_requests()方法时,默认从此列表开始爬取
  • custom_settings:专属于本Spider的配置的字典。此配置在运行此Spider时将覆盖项目全局的设置。因为设置必须在初始化之前更新,所以必须将其定义为类属性
  • logger:使用Spider创建的Python日志器,方法变属性。可以使用它来发送日志消息

5.Spider类的常用方法

  • from_crawler():Scrapy用于创建spider的类方法,一般不用覆盖
  • start_requests():用于生成初始请求,只会被调用一次,必须返回一个iterable(可迭代对象)。默认使用start_urls属性里的URL来构造GET请求格式的Request。深层次爬取时,启动阶段需要POST请求格式登录网站,获取用户权限,所以重写此方法,在发送POST请求时使用scrapy.FormRequest()方法
  • parse():当Response没有指定回调函数时,该方法是Scrapy处理Response的默认方法。它负责处理Response,返回新的Request和Item的可迭代对象。必须重写否则会报错
  • closed():spider关闭时被调用的方法。用于释放占用的资源

四、CrawlSpider

1.简介

CrawlSpider是Scrapy提供的通用Spider,可以指定URL爬取规则,自动生成Request实现页面的爬取,爬取规则由专门的数据结构Rule表示,Rule里包含提取和跟进页面的配置

2.创建方法

scrapy genspider -t crawl <name> <domain>

例如:scrapy genspider -t crawl js www.jianshu.com

在spiders文件夹下创建jianshu.py文件

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class JsSpider(CrawlSpider):
    name = 'js'
    allowed_domains = ['www.jianshu.com']
    start_urls = ['http://www.jianshu.com/']

    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        item = {}
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        #item['name'] = response.xpath('//div[@id="name"]').get()
        #item['description'] = response.xpath('//div[@id="description"]').get()
        return item

2.属性与方法

CrawlSpider类继承自Spider类,除了Spider类的所有方法和属性,还提供下面的方法和属性

  • rules:定义爬取规则的属性,是包含一个或多个Rule对象的列表。即使只有一个Rule实例,也要用逗号分隔。每个Rule对爬取网站的动作都有定义,CrawlSpider会读取rules的每个Rule并进行解析
  • parse_start_url(response):当start_url的请求返回时被调用,功能是分析Response并返回Item对象或Request对象,是可重写的方法

4.Rule类的参数

class Rule(object):
    def __init__(self, link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
  • link_extractor:是LinkExtractor对象。其定义了如何从爬取到的页面提取链接生成Request
  • callback:回调函数。每次从link_extractor中获取链接时被调用,其接收一个Response作为第一个参数,并返回Item或Request对象。应尽量避免使用parse()做回调函数,因为CrawlSpider使用parse()实现其逻辑,如果覆盖了parse(),CrawlSpider将会运行失败
  • cb_kwargs:包含传递给回调函数的参数的字典
  • follow:布尔值,指定是否根据此规则提取的每个响应中跟踪链接
  • process_links:用于过滤链接的回调函数
  • process_request:用于过滤请求的回调函数

5.LinkExtractor类的参数

class LxmlLinkExtractor(FilteringLinkExtractor):
    def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(),
                 tags=('a', 'area'), attrs=('href',), canonicalize=False,
                 unique=True, process_value=None, deny_extensions=None, restrict_css=(),
                 strip=True, restrict_text=None):
  • allow:正则表达式,满足的URL被提取出来
  • deny:正则表达式,满足的URL被排除,优先级高于allow
  • allow_domains:允许的域名,str或list
  • deny_domains:排除的域名,str或list
  • restrict_xpaths:xpath表达式,满足的URL被提取出来,str或list
  • restrict_css:css选择器,满足的URL被提取出来,str或list
  • tags:提取指定标记下的链接,默认为a,area
  • attrs:提取拥有满足属性的链接,默认为href
  • unique:是否过滤相同的URL
  • process_value:值处理函数,优先级大于allow

6.CrawlSpider URL去重

CrawlSpider的URL去重是基于CrawlSpider类里面的私有方法_requests_to_follow()

def _requests_to_follow(self, response):
    if not isinstance(response, HtmlResponse):	# 如果接受的response不是HtmlResponse对象就跳出
        return
    seen = set()
    for n, rule in enumerate(self._rules):
        links = [lnk for lnk in rule.link_extractor.extract_links(response)
                 if lnk not in seen]		# 对生成的Request查重
        if links and rule.process_links:
            links = rule.process_links(links) # 利用process_links()过滤
            for link in links:
                seen.add(link)
                request = self._build_request(n, link)
                yield rule._process_request(request, response)

7.实例:爬取简书文章数据

通过CrawlSpider类,爬取简书网站文章数据:作者、标题、发布时间、阅读数

items.py

import scrapy


class JianshuItem(scrapy.Item):
    author = scrapy.Field()
    title = scrapy.Field()
    release_time = scrapy.Field()
    pageview = scrapy.Field()

js.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from jianshu.items import JianshuItem


class JsSpider(CrawlSpider):
    name = 'js'
    # allowed_domains = ['www.jianshu.com']
    start_urls = ['https://www.jianshu.com/']
    rules = (
        Rule(LinkExtractor(allow=r'https://www.jianshu.com/p/\w+'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        item = JianshuItem()
        item['author'] = response.xpath('//span[@class="_22gUMi"]/text()').extract_first()
        item['title'] = response.xpath('//h1[@class="_1RuRku"]/text()').extract_first()
        item['release_time'] = response.xpath('.').re('"first_shared_at":(\d+),')[0]
        item['pageview'] = response.xpath('.').re('"views_count":(\d+)')[-1]
        yield item

settings.py

ROBOTSTXT_OBEY = False

DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11'
}

五、请求与响应

1.Request

Scrapy.http.Request类是scrapy框架中Request的基类

class Request(object_ref):
    def __init__(self, url, callback=None, method='GET', headers=None, body=None,
                 cookies=None, meta=None, encoding='utf-8', priority=0,
                 dont_filter=False, errback=None, flags=None, cb_kwargs=None)
  • Request对象的参数

    • url(string):请求的URL
    • callback(callable):回调函数
    • method(string):HTTP请求方式,默认为’GET’
    • meta(dict):Request.meta属性的初始值
    • body(str or unicode):请求体。如果没有传参,默认为空字符串
    • headers(dict):请求的请求头
    • cookies(dirt or list):请求的cookie信息
    • encoding(string):请求的编码,默认为’utf-8’
    • priority(int):请求的优先级(默认为0),被调度器用来安排处理请求的顺序,数字越大优先级越高(可以为负)
    • dont_filter(boolean):表示调度程序不应过滤此请求(用于多次执行相同请求,小心掉入爬虫循环)
    • errback(callable):在处理请求时引发任何异常时被调用的函数
    • flags(list):发送给请求的标志,可用于日志记录或类似目的
  • Request对象属性和方法

    • url:请求的URL的字符串。该属性是只读的,更改请求使用的URL replace()
    • method:HTTP请求方式
    • headers: 类似字典的对象,包含请求头信息
    • body:请求正文的string。该属性是只读的,更改请求使用的URL replace()
    • meta:跟随请求并包含元数据的字典,可往其中添加字段
    • copy():返回一个新的请求,该请求是复制此请求的副本
    • replace([ URL,method,headers,body,cookies,meta,encoding,dont_filter,callback,errback] ) :可替换Request中相对应的内容,返回一个新的request

2.FormRequest(登录操作)

FormRequest类的基类是Request,它专门用来处理HTML表单,适合用来完成登录操作

在处理隐藏表单时,FormRequest类提供了一个类方法FormResponse

class FormRequest(Request):
    ...
    
    @classmethod
    def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=None,clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs)
    
    ...
  • FormResponse的参数
    • response(Responseobject):包含HTML表单的响应
    • formname(string):如果给定,将使用name属性设置为此值的表单,否则为None
    • formid(string):如果给定,将使用id属性设置为此值的表单,否则为None
    • formxpath(string):如果给定,将使用与xpath匹配的第一个表单,否则为None
    • formnumber(整数):当响应包含多个表单时将使用第几个表单
    • formdata(dict):要在表单数据中覆盖的字段
    • formcss(string):如果给定,将使用与css选择器匹配的第一个表单,否则为None
    • clickdata(dict):用于查找单击控件的属性
    • dont_click(boolean):如果为True,将提交表单数据而不单击任何元素

3.实例:豆瓣登录

import scrapy


class DbSpider(scrapy.Spider):
    name = 'db'
    start_urls = ['https://accounts.douban.com/passport/login']
    login_url = 'https://accounts.douban.com/passport/login'

    def parse(self, response):
        formdata = {
            "name": "18340760809",
            "password": "zzh123456",
            "remember": "false",
        }
        yield scrapy.FormRequest(self.login_url, formdata=formdata, callback=self.login_after)

    def login_after(self, response):
        res = response.xpath('//a[@class="bn-more"]/span/text()').extract_first()
        if res is None:
            print("登录失败")
        else:
            print("登陆成功,当前账户为:%s" % res)

4.Response

scrapy.http.Response类是scrapy框架中Response的基类

class Response(object_ref):
    def __init__(self, url, status=200, headers=None, body=b'', flags=None, request=None)

属性和方法:

url:只读属性,响应的URL

status:响应码

headers:响应头

body:响应体

request:产生此响应的请求

meta:Request.meta属性的初始值

flags:附加在Response上的标记

copy():复制出一个新的Response实例

replace([ url,status,headers,body,request,flags,cls ] ):替换掉Response中相对应的内容,返回一个新的Response实例

urljoin(url):URL拼接,用来将Response.url和一个相对的URL,构成一个绝对的URL

follow(url):自动进行URL拼接,其中调用了urljoin(url)方法

5 .实例:爬取腾讯招聘招聘信息

模拟爬取腾讯招聘招聘信息:工作、地点、类型、详情(现该网站已经有反爬,因此以下代码已经失效,重点在于体验meta传播过程)

ct.py

# -*- coding: utf-8 -*-
import scrapy
from ..items import CareersTencentItem


class CtSpider(scrapy.Spider):
    name = 'ct'
    # allowed_domains = ['https://careers.tencent.com/search.html']
    start_urls = ['https://careers.tencent.com/search.html']

    def parse(self, response):
        trs = response.xpath('//div[@class="recruit-list"]/a[@class="recruit-list-link"]')
        for i in trs:
            item = CareersTencentItem()
            item['job_name'] = response.xpath('.//h4[@class="recruit-title"]/text()]').extract_first()
            item['job_addr'] = response.xpath('.//p[@class="recruit-tips"]/span[2]/text()').extract_first()
            item['job_type'] = response.xpath('.//p[@class="recruit-tips"]/span[3]/text()').extract_first()
            url_detail = response.xpath('.//div[@class="share-list"]/div[3]/@id').extract_first()
            
            yield scrapy.Request(url='https://careers.tencent.com/search.html?postId=%d' % url_detail,callback=self.parse_detail, meta={'job_item': item})
        # 请求下一页
        next_url = response.xpath('//ul[@class="page-list"]/li[@class="page-li active"]/span/text()').extract_first()
        if next_url:
            yield scrapy.Request(url='https://careers.tencent.com/search.html?index=%d' % next_url, callback=self.parse)

    def parse_detail(self, response):
        item = response.meta['job_item']
        item['detail'] = response.xpath('//li[@class="explain-item"]/text()').extract()
        yield item

items.py

import scrapy


class CareersTencentItem(scrapy.Item):
    job_name = scrapy.Field()
    job_addr = scrapy.Field()
    job_type = scrapy.Field()
    job_detail = scrapy.Field()

6.日志的配置和使用

(1).在spider中记录
def parse(self, response):
	self.logger.info("这是一个info")
(2).在其他组件中记录
import logging

logger = logging.getLogger("my_logger")
logging.warning("这是一个warning")
(3).settings.py中配置日志记录

这些设置可用于配置日志记录:

  • LOG_FILE:日志输出文件,如果为None就打印在控制台
  • LOG_ENABLED:是否启用日志,默认True
  • LOG_ENCODING:日期编码,默认utf-8
  • LOG_LEVEL:日志等级,默认debug
  • LOG_FORMAT:日志格式
  • LOG_DATEFORMAT:日志日期格式
  • LOG_STDOUT:日志标准输出,默认False,如果True所有标准输出(print)都将写入日志中
  • LOG_SHORT_NAMES:短日志名,默认为False,如果True将不输出组件名
LOG_FILE:'log.log'
LOG_ENABLED:True
LOG_ENCODING:'utf-8'
LOG_LEVEL:'INFO'
LOG_FORMAT:"%(asctime)s-%(levelname)s-%(message)s"
LOG_DATEFORMAT:"%Y-%m-%d  %H:%M:%S"
LOG_STDOUT:False
LOG_SHORT_NAMES:False

六、Downloader Middlewares

1.简介

下载中间件是实现了特殊方法的类,用于全局修改Scrapy的Request和Response,定制自己的爬虫(修改User-Agent、处理重定向、设置代理、设置cookie等)

2.内置下载中间件

官方文档:https://docs.scrapy.org/en/latest/topics/downloader-middleware.html

DOWNLOADER_MIDDLEWARES_BASE变量定义了Scrapy的内置下载中间件,它是字典格式,键是Scrapy内置的下载中间件的类路径,值是调用的优先级(正整数0-1000),值越小越靠近引擎

# 这是默认的值
DOWNLOADER_MIDDLEWARES_BASE = {
    'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
    'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
    'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
    'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
    'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
    'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
    'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
    'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
    'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
    'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}

3.方法

不是所有的方法都需要定义,如果没有定义方法,则在Scrapy中相当于下载中间件没有修改传递的对象

from scrapy import signals


class DoubanDownloaderMiddleware(object):
    
    @classmethod
    def from_crawler(cls, crawler):		# Scrapy用此方法创建你的Spiders对象
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        return None

    def process_response(self, request, response, spider):
        return response

    def process_exception(self, request, exception, spider):
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)
(1).process_request(request, spider)

在Request到下载器之前对Request进行处理的方法

  • 参数
    • request:被处理的Request对象
    • spider:此Request对应的Spider
  • 返回类型
    • None:正常执行其他下载中间件的此方法
    • request:停止执行低优先级的其他下载中间件,将此request重新放入调度器队列,等待其被调度
    • response:跳过更低级别的其他下载中间件,直接开始依次执行process_response()方法
    • IgnoreRequest异常:直接开始依次执行process_exception()方法
(2).process_response(request, response, spider)

在Response到达Spiders之前对Response进行处理的方法

  • 参数
    • request:此Response对应的Request
    • response:被处理的Response对象
    • spider:此Response对应的Spider
  • 返回类型
    • request:停止执行低优先级的其他下载中间件,将此request重新放入调度器队列,等待其被调度
    • response:正常执行其他下载中间件的此方法
    • IgnoreRequest异常:直接开始依次执行process_exception()方法
(3).process_exception(request, exception, spider)

当Downloader或者process_request()方法抛出异常时调用此方法

  • 参数
    • request:被处理的Request对象
    • spider:此Request对应的Spider
  • 返回类型
    • None:正常执行其他下载中间件的此方法
    • request:停止执行低优先级的其他下载中间件,将此request重新放入调度器队列,等待其被调度
    • response:跳过更低级别的其他下载中间件,直接开始依次执行process_response()方法
(4).from_crawler(cls, crawler)

类方法,参数是crawler,通过crawler对象可以拿到Scrapy的所有核心组件

4.激活下载中间件

在settings.py中对DOWNLOADER_MIDDLEWARES进行设置,会与Scrapy内置的下载中间件DOWNLOADER_MIDDLEWARES_BASE合并,但是不会覆盖,依旧按照优先级执行

如果想要覆盖某项,直接将DOWNLOADER_MIDDLEWARES中设置此项使其优先级在内置下载中间件之后即可

# 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
DOWNLOADER_MIDDLEWARES = {
    'douban.middlewares.RandomUserAgentMiddleware': 900,
}

或者直接将其对应的内置下载中间件中的此项在DOWNLOADER_MIDDLEWARES中设置为None即可

DOWNLOADER_MIDDLEWARES = {
	'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
	'douban.middlewares.RandomUserAgentMiddleware': 300,
}

5.搭建UA池

middlewares.py

from scrapy import signals
import random


class RandomUserAgentMiddleware(object):

    def __init__(self, user_agents):
        self.user_agents = user_agents

    @classmethod
    def from_crawler(cls, crawler):
        # 在settings.py文件中加载MY_USER_AGENTS的值
        s = cls(user_agents=crawler.settings.get('MY_USER_AGENTS'))
        return s

    def process_request(self, request, spider):
        # 随机设置User-Agent的值
        agent = random.choice(self.user_agents)
        # 将其赋给Request
        request.headers['User-Agent'] = agent
        # 如果设置代理IP通过meta传参
        # proxy = random.choice(self.proxy)
        # request.meta['proxy'] = proxy
        return None

settings.py

# 激活UA池
DOWNLOADER_MIDDLEWARES = {
	'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
	'douban.middlewares.RandomUserAgentMiddleware': 300,
}
# UA池
MY_USER_AGENTS = [
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
        "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
        "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
        "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
        "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
        "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
        "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
        "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
        "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
        "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]

利用scrapy shell https://httpbin.org测试即可

七、Spider Middlewares(使用频率低)

1.简介

蜘蛛中间件是实现了特殊方法的类,用于下载器生成的Response传到蜘蛛之前处理Response,蜘蛛生成的Request传到调度器之前处理Request,蜘蛛生成的Item传到Item管道之前处理Item,但是一般都在蜘蛛中定义,所以其使用频率很低

2.内置蜘蛛中间件

官方文档: https://docs.scrapy.org/en/latest/topics/spider-middleware.html

SPIDER_MIDDLEWARES_BASE变量定义了Scrapy的内置蜘蛛中间件,它是字典格式,键是Scrapy内置的蜘蛛中间件的类路径,值是调用的优先级(正整数0-1000),值越小越靠近引擎

SPIDER_MIDDLEWARES_BASE = {
    'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
    'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
    'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
}

3.方法

不是所有的方法都需要定义,如果没有定义方法,则在Scrapy中相当于蜘蛛中间件没有修改传递的对象

from scrapy import signals

class DoubanSpiderMiddleware(object):

    @classmethod
    def from_crawler(cls, crawler):
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        return None

    def process_spider_output(self, response, result, spider):
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):
        pass

    def process_start_requests(self, start_requests, spider):
        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)
(1).process_spider_input(response, spider)

当Response被蜘蛛中间件处理时执行的方法

  • 参数
    • response:被处理的Response
    • spider:该Response的Spider
  • 返回类型
    • None:正常继续处理该Response
    • 异常:跳过其他蜘蛛中间件的此方法
(2).process_spider_output(response, result, spider)

当蜘蛛处理Response返回结果时执行的方法

  • 参数
    • response:生成该输出的Response
    • result:包含Request或者Item对象的可迭代对象
    • spider:该Response的Spider
  • 返回类型
    • 包含Request或者Item对象的可迭代对象(必须)
(3).process_spider_exception(response, exception, spider)

当蜘蛛或蜘蛛中间件的process_spider_input()方法抛出异常时执行的方法

  • 参数
    • response:处理时抛出异常的Response
    • exception:被抛出的异常
    • spider:抛出该异常的Spider
  • 返回类型
    • None:正常继续处理该异常,调用其他蜘蛛中间件的此方法
    • 可迭代对象:调用其他蜘蛛中间件的process_spider_output()方法
(4).process_start_requests(start_requests, spider)

当蜘蛛处理新的Request时执行的方法

  • 参数
    • start_requests:包含Request的可迭代对象
    • spider:start_requests所属的Spider
  • 返回类型
    • 包含Request对象的可迭代对象(必须)

4.激活蜘蛛中间件

在settings.py中对SPIDER_MIDDLEWARES进行设置

SPIDER_MIDDLEWARES = {
   'douban.middlewares.DoubanSpiderMiddleware': 543,
}

八、Item Pipelin

1.简介

Item Pipeline的主要用途是:

  • 清理HTML数据
  • 验证爬取数据,检查爬取字段
  • 查重并删除重复内容
  • 将爬取结果保存到数据库

2.方法

(1).process_item(item, spider)

必须实现的方法,被定义的Item管道会默认调用此方法对Item进行处理

  • 参数
    • item:被处理的Item
    • spider:生成该Item的Spider
  • 返回类型
    • Item对象:此Item被低优先级的Item管道的此方法继续处理
    • DropItem异常:丢弃此Item,不再进行处理
(2).open_spider(spider)

Spider开启的时候被自动调用的方法,此处可以开启数据库连接或打开文件

(3).close_spider(spider)

Spider关闭的时候被自动调用的方法,此处可以关闭数据库连接或关闭文件

3.激活Item管道

在settings.py中对ITEM_PIPELINES进行设置

ITEM_PIPELINES = {
   'douban.pipelines.DoubanPipeline': 300,
}

九、settings

1.优先级

  • 命令行选项(优先级最高)
  • 设置per-spider
  • 项目设置模块
  • 各命令默认设置
  • 默认全局设置(低优先级)

2.settings.py

# Scrapy settings for one project

# 项目名称
BOT_NAME = 'one'

SPIDER_MODULES = ['one.spiders']
NEWSPIDER_MODULE = 'one.spiders'


# 用户UA
#USER_AGENT = 'one (+http://www.yourdomain.com)'

# 是否遵循robots协议
ROBOTSTXT_OBEY = True

# 配置由Scrapy执行的最大并发请求(默认值:16)
#CONCURRENT_REQUESTS = 32

# 为同一网站的请求配置延迟(默认:0)
#DOWNLOAD_DELAY = 3

# 最多同时并发处理每个域名、IP数
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16

# 是否启用cookies
#COOKIES_ENABLED = False

# 是否启用远程登录控制台
#TELNETCONSOLE_ENABLED = False

# 覆盖默认的请求头
#DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
#}

# 爬虫中间件配置
#SPIDER_MIDDLEWARES = {
#    'one.middlewares.OneSpiderMiddleware': 543,
#}

# 下载中间件配置
#DOWNLOADER_MIDDLEWARES = {
#    'one.middlewares.OneDownloaderMiddleware': 543,
#}

# 启用或禁用扩展
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
#    'scrapy.extensions.telnet.TelnetConsole': None,
#}

# 项目管道配置
#ITEM_PIPELINES = {
#    'one.pipelines.OnePipeline': 300,
#}

# 启用和配置自动节流阀扩展(默认禁用)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# 初始下载延迟
#AUTOTHROTTLE_START_DELAY = 5
# 在高延迟情况下设置的最大下载延迟
#AUTOTHROTTLE_MAX_DELAY = 60
# 每个远程服务器并行发送的请求的平均数量
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# 是否显示收到的每个响应的节流状态
#AUTOTHROTTLE_DEBUG = False

# 启用和配置HTTP缓存(默认禁用)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

十、项目准备工作

1.项目需求

  • 设计数据库用于存储
  • 抓取内容,并自动入库
  • 要求分布式部署
  • 定时增量爬取

2.设计数据库

Navicat是一套快速、可靠并价格相当便宜的数据库管理工具,以直觉化的图形用户界面而建的,可以用来对本机或远程的 MySQL、SQL Server、SQLite、Oracle 及 PostgreSQL 数据库进行管理及开发

3.爬取思路

  • 分析网站结构,决定爬取流程
  • 先爬取标题信息,并入库,获取id
  • 再爬取详细信息,根据id进行入库
  • 设置爬取频率
  • 加上UA池、代理池、cookie池
  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值