洗礼灵魂,修炼python(72)--爬虫篇—爬虫框架:Scrapy

题外话:

前面学了那么多,相信你已经对python很了解了,对爬虫也很有见解了,然后本来的计划是这样的:(请忽略编号和日期,这个是不定数,我在更博会随时改的)

上面截图的是我的草稿

 

然后当我开始写博文的时候,我发现讲解PhantomJS的话,会涉及到JS代码,而相信跟着我的学习路线从小白上来的,应该都还没学过JS吧,说到JS,那么和Phantom很像的一个模块casperjs,也要跟着提点下,那么还要从JS开始讲解

然后说到PyQuery,其又几乎和JQuery差不多,又要提下JQuery

接着爬虫框架pyspider只支持32位操作系统,我的电脑现在是64位的系统,真要讲解的话,又得重装系统或者在虚拟机下操作

还有个最大的问题,爬虫篇确实延伸得有点多了,这路线走下来,感觉爬虫篇都占了大半了,所以我打算早点结束了,并且我现在也在学习阶段,时间不太多,更博时间也少了。

 

真不是我懒或者不愿意和大家分享,要把以上的东西说明白,确实需要花些时间,而渐渐的优点偏离我的初衷和本板块的主线。

 

所以我决定直接讲解爬虫框架Scrapy,其他的暂时不讲解了,以后有时间再讲解了,如果你们确实对爬虫这方面感兴趣(如果你想从事爬虫工程师的工作以上的真需要掌握下),可以网上找资料或者去这里看一位大神的文章:传送门

 

 

总之,那几个模块或者框架暂时不更了,后期有时间再更,目前暂时以Scrapy框架作为爬虫篇的收尾吧,后面开始python全栈开发和项目实战了

 

 

 

Scrapy框架

1.简介

1)什么是框架:

  • 提供形状或强度的结构系统(如屋架)
  • 比喻事物的组织、结构

在IT圈里,框架指为解决一个开放性问题而设计的具有一定约束性的支撑结构在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的方案

通俗的理解,框架就是一套体系,基本整合某一方面的大部分功能,使用它一个就够了,不需要再用其他的多个程序和软件来组合运行处理问题。但是框架也不是万能的,只能完成大部分工作

2)Scrapy框架:

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的web应用框架。它为爬虫提供更灵活更全面的工具和用法,使爬虫工作变得方便,当使用它时,已经默认为你设置好大部分准备工作。

Scrapy 使用了 Twisted异步网络库来处理网络通讯。整体架构大致如下:

(一张老掉牙的图片)

 

Scrapy主要包括了以下组件:

  • 引擎(Scrapy):用来处理整个系统的数据流处理, 触发事务(框架核心)
  • 调度器(Scheduler):用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
  • 下载器(Downloader):用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
  • 爬虫(Spiders):爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
  • 项目管道(Pipeline):负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
  • 下载器中间件(Downloader Middlewares):位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
  • 爬虫中间件(Spider Middlewares):介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
  • 调度中间件(Scheduler Middewares):介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应

 

Scrapy运行流程大概如下:

  • 引擎从调度器中取出一个链接(URL)用于接下来的抓取
  • 引擎把URL封装成一个请求(Request)传给下载器
  • 下载器把资源下载下来,并封装成应答包(Response)
  • 爬虫解析Response
  • 解析出实体(Item),则交给实体管道进行进一步的处理
  • 解析出的是链接(URL),则把URL交给调度器等待抓取

 

2.安装/配置

注意:

1.python3目前还不能完美支持Scrapy(下面都是在python2上进行)

2.windows平台需要依赖pywin32,请根据自己系统32/64位选择下载安装,安装pywin32链接(你直接点这个链接,浏览器就会开始下载了,已经给你们选好下载包,下载完成双击,一路下一步就行)

 

使用pip install scrapy 安装:

 

 

安装好后,在cmd下运行测试是否安装成功:

 

至此,Scrapy框架已经安装完成,下面就开始使用了

 

3.简单使用

1)创建项目

在cmd下,进入你希望的路径,使用命令:scrapy startproject (项目名称)  创建项目

 

然后scrapy会自动创建一些东西:

自动创建文件夹:

 

可以用pycharm一目了然:

 

文件含义:

  • scrapy.cfg:项目的配置信息,主要为Scrapy命令行工具提供一个基础的配置信息。(真正爬虫相关的配置信息在settings.py文件中)
  • items.py:设置数据存储模板,用于结构化数据,如:Django的Model
  • pipelines:数据处理行为,如:一般结构化的数据持久化
  • settings.py:配置文件,如:递归的层数、并发数,延迟下载等
  • spiders:爬虫目录,如:创建文件,编写爬虫规则(爬虫程序就放在此文件夹下 )

2)编写代码

注意:为了创建一个Spider,您必须继承scrapy.spiders.Spider类(后面有详解,姑且这么认定就行)

 

在spiders目录中新建 sc_test.py 文件

 

import scrapy

class bdspider(scrapy.spiders.Spider):
    name = 'baidu'
    allow_domains = ['baidu.com']
    start_urls = [
        'http://www.baidu.com',
        'http://news.baidu.com',
        'http://zhidao.baidu.com'
    ]
    def parse(self,response):
        filename = response.url.split('/')[-2]
        f = open('filename','wb')
        f.write(response.body)
        f.close()

 

在爬虫项目的根目录下,也就是你刚才创建的项目文件夹下,执行爬虫程序命令:scrapy crawl name(此name即为刚才自定义里的name,比如我上面代码里的‘baidu')

scrapy 就是框架名嘛,crawl就是爬行的意思,这条命令就是开始爬虫程序

 运行结果:

G:\programme\Python\python project\scrapytest>scrapy crawl baidu
2017-12-12 13:56:13 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapyte
st)
2017-12-12 13:56:13 [scrapy.utils.log] INFO: Overridden settings: {'NEWSPIDER_MO
DULE': 'scrapytest.spiders', 'SPIDER_MODULES': ['scrapytest.spiders'], 'ROBOTSTX
T_OBEY': True, 'BOT_NAME': 'scrapytest'}
2017-12-12 13:56:13 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2017-12-12 13:56:13 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-12 13:56:14 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-12 13:56:14 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-12-12 13:56:14 [scrapy.core.engine] INFO: Spider opened
2017-12-12 13:56:14 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pag
es/min), scraped 0 items (at 0 items/min)
2017-12-12 13:56:14 [scrapy.extensions.telnet] DEBUG: Telnet console listening o
n 127.0.0.1:6023
2017-12-12 13:56:14 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.ba
idu.com/robots.txt> (referer: None)
2017-12-12 13:56:14 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by
 robots.txt: <GET http://www.baidu.com>
2017-12-12 13:56:14 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://news.b
aidu.com/robots.txt> (referer: None)
2017-12-12 13:56:14 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by
 robots.txt: <GET http://news.baidu.com>
2017-12-12 13:56:14 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://zhidao
.baidu.com/robots.txt> (referer: None)
2017-12-12 13:56:14 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (
301) to <GET https://zhidao.baidu.com/> from <GET http://zhidao.baidu.com>
2017-12-12 13:56:15 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://zhida
o.baidu.com/> (referer: None)
2017-12-12 13:56:15 [scrapy.core.engine] INFO: Closing spider (finished)
2017-12-12 13:56:15 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 2,
 'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 2,
 'downloader/request_bytes': 1205,
 'downloader/request_count': 5,
 'downloader/request_method_count/GET': 5,
 'downloader/response_bytes': 57574,
 'downloader/response_count': 5,
 'downloader/response_status_count/200': 4,
 'downloader/response_status_count/301': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 12, 12, 5, 56, 15, 360000),
 'log_count/DEBUG': 8,
 'log_count/INFO': 7,
 'response_received_count': 4,
 'scheduler/dequeued': 4,
 'scheduler/dequeued/memory': 4,
 'scheduler/enqueued': 4,
 'scheduler/enqueued/memory': 4,
 'start_time': datetime.datetime(2017, 12, 12, 5, 56, 14, 19000)}
2017-12-12 13:56:15 [scrapy.core.engine] INFO: Spider closed (finished)

 (时间暂且忽略,因为我是为了和后面的使用代码运行作对比而补充的,本来不想给出来的,因为占空间,也没多大的作用)

 

 

(只截取了部分,上面显示的都是日志 )

你可以不让它显示日志:使用命令:scrapy crawl name --nolog:

 

再看这部分代码:

 

这里面的请求url正好就是之前定义的start_urls里的url

其中我圈出来的robots.txt,还有forbidden什么什么的,这些是什么意思,robot就是机器人的意思,robots.txt就是一个协议,大部分网站都会有的就是防爬虫程序,大概意思就是请求被robots.txt协议拒绝。

可以直接访问一下这个文件:

(图片只截取了部分)

里面的User_agent就是请求头部信息,只要有这些信息就直接disallow(拒绝的意思)。

 

当然你要知道scrapy是个框架啊,这种简单的防爬机制怎么能难得住scrapy,在setting.py文件里可以修改的,后面再做详解

 

先来解释下,当我运行这条命令scray  crawl name 时,都发生了什么

Scrapy给Spider的start_urls属性中的每个URL创建了一个spider.request对象,并将parse方法作为回调函数(callback)赋值给了request。Request对象经过调度,执行生成scrapy.http.response对象并送回给spider的parse方法。

 

所以,你可能看着代码有点云里雾里,你只要修改部分就行,其他的scrapy框架为你自动设置,这就是scrapy的特性,这就是框架的好处

 

相信有朋友觉得在终端下手动执行命令来运行scrapy爬虫有点麻烦了,是的,python这么高端的,怎么会用这么低级的运行方式呢?

 

方法有两个:

1.在pycharm里可以配置(详细的就自己查了,不难)

2.写一个运行文件run.py

此run.py必须放在创建项目的根目录下,比如我这里的根目录就是scrapytest

 

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from spiders.sc_test import bdspider

settings =get_project_settings()
process = CrawlerProcess(settings=settings)

process.crawl(bdspider)
process.start()

 

运行结果:

2017-12-12 13:55:06 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapytest)
2017-12-12 13:55:06 [scrapy.utils.log] INFO: Overridden settings: {'NEWSPIDER_MODULE': 'scrapytest.spiders', 'SPIDER_MODULES': ['scrapytest.spiders'], 'ROBOTSTXT_OBEY': True, 'BOT_NAME': 'scrapytest'}
2017-12-12 13:55:06 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2017-12-12 13:55:07 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-12 13:55:07 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-12 13:55:07 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-12-12 13:55:07 [scrapy.core.engine] INFO: Spider opened
2017-12-12 13:55:07 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-12 13:55:07 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-12-12 13:55:08 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.baidu.com/robots.txt> (referer: None)
2017-12-12 13:55:08 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET http://www.baidu.com>
2017-12-12 13:55:08 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://news.baidu.com/robots.txt> (referer: None)
2017-12-12 13:55:08 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET http://news.baidu.com>
2017-12-12 13:55:08 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://zhidao.baidu.com/robots.txt> (referer: None)
2017-12-12 13:55:08 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET https://zhidao.baidu.com/> from <GET http://zhidao.baidu.com>
2017-12-12 13:55:09 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://zhidao.baidu.com/> (referer: None)
2017-12-12 13:55:09 [scrapy.core.engine] INFO: Closing spider (finished)
2017-12-12 13:55:09 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 2,
 'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 2,
 'downloader/request_bytes': 1205,
 'downloader/request_count': 5,
 'downloader/request_method_count/GET': 5,
 'downloader/response_bytes': 57227,
 'downloader/response_count': 5,
 'downloader/response_status_count/200': 4,
 'downloader/response_status_count/301': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 12, 12, 5, 55, 9, 578000),
 'log_count/DEBUG': 8,
 'log_count/INFO': 7,
 'response_received_count': 4,
 'scheduler/dequeued': 4,
 'scheduler/dequeued/memory': 4,
 'scheduler/enqueued': 4,
 'scheduler/enqueued/memory': 4,
 'start_time': datetime.datetime(2017, 12, 12, 5, 55, 7, 921000)}
2017-12-12 13:55:09 [scrapy.core.engine] INFO: Spider closed (finished)

 

对比上面在终端下的运行结果是一样的

 

3)定义和设置item  (可选步骤,没有这一步一样可以运行,不过稍微大型点的爬虫项目建议加上这一步)

item是保存爬取到的数据的容器,使用方法和python字典类似, 它还提供了额外保护机制来避免拼写错误导致的未定义字段错误。

首先要根据需求从baidu.com获取到的数据对item进行建模,我们需要从百度中获取名字,url,以及网站的描述。 对此,在item中定义相应的字段。编辑scrapytest目录中的item.py文件

import scrapy

class scrapytestitem(scrapy.Item):
    title = scrapy.Field()  #标题
    link = scrapy.Field()   #url  
    desc = scrapy.Field()   #描述

scrapy.Item的用法与python中的字典用法基本一样,只是做了一些安全限制,属性定义使用Field,这里只是进行了声明,而不是真正的属性,使用的时候通过键值对操作,但不支持属性访问,意味着所有的属性赋值都得用字符串

 

利用上面定义的title,link,desc则可以对parse方法进行修改,得到需要得到的值:(下面的是伪代码,具体代码根据具体情况来)

 

import scrapy

class bdspider(scrapy.spiders.Spider):
    name = 'baidu'
    allow_domains = ['baidu.com']
    start_urls = [
        'http://www.baidu.com',
        'http://news.baidu.com',
        'http://zhidao.baidu.com'
    ]
    def parse(self,response):
        for i in response.xpath('//div/ul')  #此处的html标签只是一个假设
        bd_item = ScrapytestItem()
        bd_item['title'] = i.xpath('li/text()').extract()
        bd_item['link'] = i.xpath('li/text()').extract()
        bd_item['desc'] = i.xpath('li/text()').extract()

 

 

 

 

4.scrapy类

前面已经对scrapy有个大概了解了,那么开始详细的scrapy类讲解了

1)scrapy.spiders.spider类(即上面创建爬虫代码继承的类)

其常用属性/方法

属性:

  • name:即爬虫的名字,它是唯一的,用于区别不同的Spider,不可以为不同的Spider设定相同的名字
  • start_urls:包含Spider在启动时进行爬取的url列表
  • parse()是spider的一个方法。 被调用时,每个初始URL完成下载后生成的response对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的request对象
  • custom_settings:自定义配置,覆盖settings.py中的默认配置(一般很少对这个属性进行修改)

 

方法

  • start_requets():启动爬虫的时候调用,默认是调用make_requests_from_url方法爬取start_urls的链接,可以在这个方法里面定制,如果重写了该方法,start_urls默认将不会被使用,可以在这个方法里面定制一些自定义的url,如登录,从数据库读取url等,本方法返回Request对象
  • make_requests_from_url():默认由start_requets调用,可以配置Request对象,返回Request对象
  • parse():response到达spider的时候默认调用,如果在Request对象配置了callback函数,则不会调用,parse方法可以迭代返回Item或者Request对象,如果返回Request对象,则会进行增量爬取

2)Request和respone对象

每个请求都是一个Request对象,Request对象定义了请求的相关信息(url, method, headers, body, cookie, priority)和回调的相关信息(meta, callback, dont_filter, errback),通常由spider迭代返回。其中meta相当于附加变量,可以在请求完成后通过respone.meta访问

请求完成后,会通过respone对象发送给spider处理,常用属性有(url, status, headers, body, request, meta)

 

详细介绍参考官网:

 

scrapy的类最常见的就这几个

 

5.提取数据

既然都能爬网站,当然希望从网页里爬取我们需要的数据,而当我们爬取大量的网页,针对某一段我们需要的数据时,如果还是用re或者BeautifulSoup的话,那就完全没必要用scrapy框架了对吧?并且这也很浪费时间,没让人失望,scrapy内部确实支持更简单的查询语法,帮助我们查询需要的数据。

  • 查询某个子标签(以a标签为例):/a
  • 查询某个子标签下的子标签(以a标签为例)://a
  • 查询标签中带有某个class属性的标签://div[@class=’fm′]:即子子孙孙中标签是div且class=‘fm’的标签
  • 查询标签中带有某个class=‘fm’并且自定义属性name=‘test’的标签://div[@class=’fm′][@name='test']
  • 查询某个标签的文本内容://div/span/text():即查询子子孙孙中div下面的span标签中的文本内容
  • 查询某个属性的值(例如查询a标签的href属性)://a/@href

不过这也并不是说scrapy有自己的一套查询语句,Scrapy是使用了一种基于 XPathCSS 表达式机制: Scrapy Selectors

 

Selector有六个基本的方法:

  • 基本的文本操作(这不废话吗)
  • dom树形结构操作:BeautifulSoup
  • re():根据传入的正则表达式对数据进行提取,返回unicode字符串list列表
  • xpath():传入xpath表达式,返回该表达式所对应的所有节点的selector list列表(scrapy默认支持选择器的功能,自带的选择器构建与lxml之上,并对其进行了改进,使用起来更为简洁明了)
  • css():传入CSS表达式,返回该表达式所对应的所有节点的selector list列表
  • extract():序列化该节点为unicode字符串并返回list(可以和xpath配套使用)

 

基本的文本操作,正则表达式,以及BeautifulSoup就不废话了,前面都讲过的

 

1)xpath:

XPpath是标准的XML文档查询语言,可以用于查询XML文档中的节点和内容,其实单独的把它拿出来也可以作爬虫操作的,与re和BeautifulSoup一样的,但因为它用的是xml文档,可能很多人用不惯(我也用不惯),所以感觉上并没有re,BeautifulSoup操作简单

Selector相当于节点,通过xpath去到子节点集合(SelectorList),可以继续搜索,通过extract方法可以取出节点的值,extract方法也可以作用于SelectorList,对于SelectorList可以通过extract_first取出第一个节点的值

A.通过text()取出节点的内容

 

B.通过@href取出节点属性值

 

 C.直接对节点取值,则是输出节点的字符串

 

2)css:

 

 

 有关css的用法,详细可见:https://www.w3.org/TR/selectors/

 

 

爬虫的通常需要在一个网页里面爬去其他的链接,然后一层一层往下爬,scrapy提供了LinkExtractor类用于对网页链接的提取,使用LinkExtractor需要使用CrawlSpider爬虫类中,CrawlSpider与Spider相比主要是多了rules,可以添加一些规则,那么这个Rule其实也是一个对象

 

6.Rule和LinkExtractor

1)Rule对象参数:

  • link_extractor:链接提取规则
  • callback:link_extractor提取的链接的请求结果的回调
  • cb_kwargs:附加参数,可以在回调函数中获取到
  • follow:表示提取的链接请求完成后是否还要应用当前规则(boolean),如果为False则不会对提取出来的网页进行进一步提取,默认为False
  • process_links:处理所有的链接的回调,用于处理从response提取的links,通常用于过滤(参数为link列表)
  • process_request:链接请求预处理(添加header或cookie等)

 

2) LinkExtractor对象参数:

  •  allow:提取符合正则表达式的链接
  • deny:拒绝符合正则表达式的链接(优先级高于allow,在开发中,一般都是拒绝优先
  • allow_domains:允许的域名(可以是str或list)
  • deny_domains:拒绝的域名(可以是str或list)
  • restrict_xpaths:提取满足XPath选择条件的链接(可以是str或list)
  • restrict_css:提取满足css选择条件的链接(可以是str或list)
  • tags:提取指定标签下的链接,默认从a和area中提取(可以是str或list)
  • attrs:提取满足拥有属性的链接,默认为href(类型为list)
  • unique:链接是否去重(类型为boolean)
  • process_value:值处理函数(优先级大于allow)

 

 注意:如果使用rules规则,请不要覆盖或重写CrawlSpider的parse方法,否则规则会失效,可以使用parse_start_urls方法

 

同样是有些伪代码的感觉,你们知道大概怎么操作就行了

from scrapy.spider import CrawlSpider,Rule
from scrapy.linkextractor import LinkExtractor

class bdnewspider(CrawlSpider):
    name ='bdnew'
    allowed_domains = ['baidu.com']
    start_urls = ['http://news.baidu.com/ent']
    rules = [
        Rule(LinkExtractor(allow=(r'http://ent.ifeng.com/a/20171212/$')),callback='parse_item'),
    ]
    def parse_item(self,response):
        pass

 结果:

G:\programme\Python\python project\scrapytest>scrapy crawl bdnew
G:\programme\Python\python project\scrapytest\scrapytest\spiders\Ruletest.py:7:
ScrapyDeprecationWarning: Module `scrapy.spider` is deprecated, use `scrapy.spid
ers` instead
  from scrapy.spider import CrawlSpider,Rule
G:\programme\Python\python project\scrapytest\scrapytest\spiders\Ruletest.py:8:
ScrapyDeprecationWarning: Module `scrapy.linkextractor` is deprecated, use `scra
py.linkextractors` instead
  from scrapy.linkextractor import LinkExtractor
<h1 class="test" style="backgroud:red">world</h1>
[u'backgroud:red']
2017-12-12 15:54:43 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapyte
st)
2017-12-12 15:54:43 [scrapy.utils.log] INFO: Overridden settings: {'NEWSPIDER_MO
DULE': 'scrapytest.spiders', 'SPIDER_MODULES': ['scrapytest.spiders'], 'ROBOTSTX
T_OBEY': True, 'BOT_NAME': 'scrapytest'}
2017-12-12 15:54:43 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2017-12-12 15:54:45 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-12 15:54:45 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-12 15:54:45 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-12-12 15:54:45 [scrapy.core.engine] INFO: Spider opened
2017-12-12 15:54:45 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pag
es/min), scraped 0 items (at 0 items/min)
2017-12-12 15:54:45 [scrapy.extensions.telnet] DEBUG: Telnet console listening o
n 127.0.0.1:6023
2017-12-12 15:54:45 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://news.b
aidu.com/robots.txt> (referer: None)
2017-12-12 15:54:45 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by
 robots.txt: <GET http://news.baidu.com/ent>
2017-12-12 15:54:46 [scrapy.core.engine] INFO: Closing spider (finished)
2017-12-12 15:54:46 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 1,
 'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 1,
 'downloader/request_bytes': 222,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 970,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 12, 12, 7, 54, 46, 67000),
 'log_count/DEBUG': 3,
 'log_count/INFO': 7,
 'response_received_count': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2017, 12, 12, 7, 54, 45, 240000)}
2017-12-12 15:54:46 [scrapy.core.engine] INFO: Spider closed (finished)

 

 

 

以上的各个机制都有不同的分工,spider负责爬虫的配置,item负责声明结构化数据

 

7.缓存

scrapy默认已经自带了缓存的功能,我们只需要配置即可,打开settings.py文件:

 

图片标注区域则是缓存设置,分别代码的意思:

# 打开缓存
HTTPCACHE_ENABLED = True 

# 设置缓存过期时间(单位:秒)
#HTTPCACHE_EXPIRATION_SECS = 0
 
# 缓存路径(默认为:.scrapy/httpcache)
HTTPCACHE_DIR = 'httpcache'
 
# 忽略的状态码
HTTPCACHE_IGNORE_HTTP_CODES = []
 
# 缓存模式(文件缓存)
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

 如果你需要设置就把前面的注释符【#】去掉就可以了

 

8.多线程

scrapy网络请求是基于Twisted,而Twisted默认支持多线程,相信在你使用命令【pip install scrapy】时,你应该注意到在安装过程中,安装过Twisted组件。

scrapy默认也是通过多线程请求的,并且支持多核CPU的并发,通常只需要配置以下参数即可:

 

# 默认Item并发数:100
CONCURRENT_ITEMS = 100
 
# 默认Request并发数:16
CONCURRENT_REQUESTS = 16
 
# 默认每个域名的并发数:8
CONCURRENT_REQUESTS_PER_DOMAIN = 8
 
# 每个IP的最大并发数:0表示忽略
CONCURRENT_REQUESTS_PER_IP = 0

 

这些参数成了默认Item并发数没有(找了很久,确实没找到,我是手动添加的),其他都在settings.py文件里面:

 

详见说明:官网文档

 

补充:

9.伪造报文头部

前面的测试里一直被拒绝访问,因为user-agent参数问题,scrapy当然可以设置user-agent参数的,有三个方法可行:

1)在settings.py里设置

 

settings.py默认的是这样的:

 

 

可以这么修改:

 

然后,如果你运行代码还是提示forbidden之类的,记得把这个参数由默认的True改为False就行:

 

 

结果:

G:\programme\Python\python project\scrapytest>scrapy crawl baidu
G:\programme\Python\python project\scrapytest\scrapytest\spiders\Ruletest.py:7:
ScrapyDeprecationWarning: Module `scrapy.spider` is deprecated, use `scrapy.spid
ers` instead
  from scrapy.spider import CrawlSpider,Rule
G:\programme\Python\python project\scrapytest\scrapytest\spiders\Ruletest.py:8:
ScrapyDeprecationWarning: Module `scrapy.linkextractor` is deprecated, use `scra
py.linkextractors` instead
  from scrapy.linkextractor import LinkExtractor
<h1 class="test" style="backgroud:red">world</h1>
[u'backgroud:red']
2017-12-12 16:33:55 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapyte
st)
2017-12-12 16:33:55 [scrapy.utils.log] INFO: Overridden settings: {'NEWSPIDER_MO
DULE': 'scrapytest.spiders', 'SPIDER_MODULES': ['scrapytest.spiders'], 'USER_AGE
NT': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko)
 Chrome/19.0.1055.1 Safari/535.24', 'BOT_NAME': 'scrapytest'}
2017-12-12 16:33:55 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2017-12-12 16:33:56 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-12 16:33:56 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-12 16:33:56 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-12-12 16:33:56 [scrapy.core.engine] INFO: Spider opened
2017-12-12 16:33:56 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pag
es/min), scraped 0 items (at 0 items/min)
2017-12-12 16:33:56 [scrapy.extensions.telnet] DEBUG: Telnet console listening o
n 127.0.0.1:6023
2017-12-12 16:33:56 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (
302) to <GET https://www.baidu.com/> from <GET http://www.baidu.com>
2017-12-12 16:33:56 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (
301) to <GET https://zhidao.baidu.com/> from <GET http://zhidao.baidu.com>
2017-12-12 16:33:56 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://news.b
aidu.com> (referer: None)
2017-12-12 16:33:56 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.b
aidu.com/> (referer: None)
2017-12-12 16:33:57 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://zhida
o.baidu.com/> (referer: None)
2017-12-12 16:33:57 [scrapy.core.engine] INFO: Closing spider (finished)
2017-12-12 16:33:57 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 1696,
 'downloader/request_count': 5,
 'downloader/request_method_count/GET': 5,
 'downloader/response_bytes': 112116,
 'downloader/response_count': 5,
 'downloader/response_status_count/200': 3,
 'downloader/response_status_count/301': 1,
 'downloader/response_status_count/302': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 12, 12, 8, 33, 57, 411000),
 'log_count/DEBUG': 6,
 'log_count/INFO': 7,
 'response_received_count': 3,
 'scheduler/dequeued': 5,
 'scheduler/dequeued/memory': 5,
 'scheduler/enqueued': 5,
 'scheduler/enqueued/memory': 5,
 'start_time': datetime.datetime(2017, 12, 12, 8, 33, 56, 371000)}
2017-12-12 16:33:57 [scrapy.core.engine] INFO: Spider closed (finished)

 

结果里已经没有forbidden和robots.txt之类的字眼了

 

2)在middlewares.py文件中设置User-Agent(也称通过改写中间件来设置User-Agent)

在middleware.py追加编写一个类,代码大概如下:

 

import random  
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware  
  
class UAMiddleware(UserAgentMiddleware):  
    def __init__(self, user_agent=''):  
        self.user_agent = user_agent  
  
    def process_request(self, request, spider):   
        if random.choice(self.user_agent_list):             
            request.headers.setdefault('User-Agent', ua)    
    user_agent_list = [\  
        "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"  
       ]  

 

然后在setting.py文件里,把这段代码:

#DOWNLOADER_MIDDLEWARES = {
#    'scrapytest.middlewares.MyCustomDownloaderMiddleware': 543,
#}

 

改成这样就行:

DOWNLOADER_MIDDLEWARES = {  
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware':None,  
    'scrapytest.middlewares.UAMiddleware':400,     #scrapytest是创建的项目名,UAMiddleware是刚才在midddleware.py文件下自定义的一个类
} 

 

结果和前面直接修改setting.py的相同,就不贴出来了

如果结果还是有forbidden之类的,同样的把前面那个True改为False就行

 

3)在scrapy主程序里直接加上User-Agent

详细操作略过,和以前的用法一样的

 

4)使用第三方user-agent库(fake-useragent)

使用pip安装好第三方库后,在setting.py文件里添加这么一段代码就行:

 

同样的,结果也相同,不再展示

 

 

其他的还有设置管道的Pipeline,还有Middleware暂时略过了,看项目来使用,一般我个人都没有用到,如果你感兴趣可以自己查查怎么用

 

以上所有的,如果你觉得还不够,可以看看scrapy的官方文档里的中文教程:传送门

 

 

posted @ 2017-12-12 17:19  Eeyhan  阅读(469)  评论(0编辑  收藏  举报