Python爬虫Scrapy笔记

这边是高级篇,基础篇在另一篇博客
https://blog.csdn.net/weixin_45304503/article/details/105581137

scrapy自带多线程,所以效率特别高

1. 框架原理

在这里插入图片描述

2. 安装

  • windows下

    法一:

    pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy
    

    现在直接安装就行了,但是去年直接安装会报错…所以去年用的是法二

    法二:
    安装scrapy以及pypiwin32 (用轮子装,win系统下要安装pypiwin32)

  • linux下

    如果是在ubuntu下,还需要安装第三方库

    sudo apt-get install python-dev python-pip libxm12-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
    

3. 创建

  1. 创建项目:‘scrapy startproject [爬虫的名字]’ (记得进入pycharmprojects的页面来进行创建)

  2. 创建爬虫:进入到项目所在的路径,执行命令:‘scrapy genspider [爬虫的名字] [爬虫的域名]’ 放在spider上创建

4. 结构

  • items.py:用来存放爬虫爬取下来的数据类型
  • middlewares.py:用来存放各种中间件的文件
  • pipelines.py:用来将items的模型存储到本地磁盘中
  • settings.py:本爬虫的一些配置信息(比如请求头、多久发送一次、ip代理池等等)
  • scrapy.cfg:项目的配置文件
  • spiders包:以后所有的爬虫,都是存放到这里面

5. 知识

5.1 基本知识:

  • response是一个scrapy.http.response.html.HtmlResponse对象,可以执行xpathcss语法来提取数据。

  • 提取出来的数据,是一个Selector或者是一个SelectorList对象。如果想要获取其中的字符串,那么应该执行getall或是get方法

  • getall方法:获取selector中的所有文本,返回的是列表

  • get方法:获取selector中的第一个文本,返回的是str类型

  • 如果数据解析回来,要传给pipline处理。那么可以使用yield关键字来返回,或是可以收集到所有的item,最后统一使用return返回。

  • item:建议在item.py中定义好模型,以后就不要使用字典了,在最后将数据变成字典就行了

  • pipeline:这个是专门用来保存数据的,其中三个方法是会经常用到的。

open_spider(self,spider):当爬虫被打开的时候就会被调用

process_item(self,item,spider):当爬虫有item传过来的时候就会被调用

close_spider(self,spider):当爬虫关闭的时候会被调用
要激活piplilne , 应该在settings.py中设置ITEM_PIPELINES将其激活.

  • JsonItemExporter:这个是每次把数据添加到内存中,最后统一写入到磁盘中
    1. 好处就是存储的数据是一个满足json规则的数据。
    2. 坏处就是如何数据量比较大,那么比较消耗内存。
from scrapy.exporters import JsonItemExporter   # 导入json导出器

class QsbkPipeline(object):
    def __init__(self):
        self.fp=open("duanzi.json",'wb')  # 以二进制的方式打开
        self.exporter=JsonItemExporter(self.fp, ensure_ascii=False,encoding='utf-8')  # 创建一个导入的对象
        self.exporter.start_exporting()  # 开始导入


    def open_spider(self,spider):  # 爬虫开始
        print("爬虫开始")

    def process_item(self, item, spider):  # item是爬虫返回的数据
        self.exporter.export_item(item)  # 用export_item来进行返回
        return item

    def close_spider(self,spider): #爬虫结束
        self.exporter.finish_exporting()
        self.fp.close()
        print("爬虫结束了")
  • JsonLinesItemExporter:这个是每次调用export_item的时候就吧这个item存储到硬盘当中。
    1. 坏处是每一个字典是一行,整个文件不是一个满足json格式的文件。
    2. 好处就是每次处理数据的时候就直接存储到硬盘当中,这样不会消耗内存,数据也比较安全。
from scrapy.exporters import JsonLinesItemExporter   
# 导入json导出器,有lines, 一行一行的来,数据量多的话就用这个

class QsbkPipeline(object):
    def __init__(self):
        self.fp=open("duanzi.json",'wb')  # 以二进制的方式打开
        self.exporter=JsonLinesItemExporter(self.fp, ensure_ascii=False,encoding='utf-8') 
            # 创建一个导入的对象
            # 这边不需要开始导入之类的
    def open_spider(self,spider):  # 爬虫开始
        print("爬虫开始")

    def process_item(self, item, spider):  # item是爬虫返回的数据
        self.exporter.export_item(item)  # 用export_item来进行返回
        return item

    def close_spider(self,spider): #爬虫结束
        # self.exporter.finish_exporting()  也不需要什么结束导入
        self.fp.close()
        print("爬虫结束了")

5.2 创建CrawlSpider爬虫:

scrapy genspider -c crawl [爬虫名字] [域名]

5.3 LinkExtractors连接提取器:

这个可以不用程序员自己提取想要的url,然后发送请求。这些工作可以交给LinkExtractors,他会在所有爬取的网面中找到满足规则的url,实现自动的爬取。

class scrapy.linkextractors.LinkExtractor(
	allow=(),    #允许的url  所有满足这个正则表达式的url都会被提取
    deny=(),	 #禁止的url  所有满足这个正则表达式的url都不会被提取
    allow_domains(),  #允许的域名  只有在这个里面指定的域名的url才会被提取
    deny_extensions=None, 
    restrict_xpaths=(),  # 严格的xpath和allow共同过滤链接
    tahs=('a','area'),
    attrs=('herf'),
    unique=True,
    process_value=None
)

5.3 Rule规则类:

class scrapy.spiders.Rule(
link_extractor,
    callback=None, #满足这个规则的url就应该执行哪个回调函数.因为CrawlSpider使用了parse作为回调函数,因此不要副高parse作为回调函数自己的回调函数
    cb_kwargs=None, 
    follow=None,   # 是否需要跟进默认True
    process_links=None,   # 从link_extractor中获取到连接后会传递给这个函数,用来过滤不需要爬取的连接
    process_request=None  
)

CrawlSpider:

需要使用LinkExtractor和Rule这两个东西决定爬虫给的具体走向

1.allow设置规则的方法:要能够限制在我们想要的url上面,不要跟其他url产生相同的正则表达式即可。

2.什么情况下使用follow:如果在爬取页面的时候,需要将满足当前条件的url再进行跟进,那么就设置为True。否则设置为False.

3.什么情况下该指定callback:如果这个url对应的页面,只是为了获取更多的url,并不需要里面的数据,那么可以不指定callback。如果想要获取url对应的页面中的数据,那么就需要指定一个callback来进行数据的处理,储存等。

关于Scrapy Shell

再爬虫中使用xpath,beautifulsoup,正则表达式,css选择器等等,但是scrapy是一个比较重的框架,每次运行起来都要等待一段时间,因此要去验证我们写的提取规则是否正确,是一个麻烦的事情,因此scrapy提供了一个shell可以方便测试规则。

在cmd打开终端,进入到scrapy项目所在的目录,然后进入到scrapy框架所在的虚拟环境中,输入命令,scrapy shell 链接。就会进入到scrapy的shell环境中,你可以跟在爬虫中的parse方法一样使用了。

1.可以方便我们做一些数据提取的测试代码

2.如果想要执行scrapy命令,那么毫无疑问,肯定是要想进入scrapy所在的环境中,我自己电脑的python环境只有一个,是定义到全局的,所以就可以直接进行命令

3.如果想要读取某个项目的配置信息,那么应该先进入到这个项目中。再执行’scrapy shell’命令

Request和Response对象

1.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):

        self._encoding = encoding  # this one has to be set first
        self.method = str(method).upper()
        self._set_url(url)
        self._set_body(body)
        assert isinstance(priority, int), "Request priority not an integer: %r" % priority
        self.priority = priority

        if callback is not None and not callable(callback):
            raise TypeError('callback must be a callable, got %s' % type(callback).__name__)
        if errback is not None and not callable(errback):
            raise TypeError('errback must be a callable, got %s' % type(errback).__name__)
        self.callback = callback
        self.errback = errback

        self.cookies = cookies or {}
        self.headers = Headers(headers or {}, encoding=encoding)
        self.dont_filter = dont_filter

        self._meta = dict(meta) if meta else None
        self._cb_kwargs = dict(cb_kwargs) if cb_kwargs else None
        self.flags = [] if flags is None else list(flags)

Request对象在我们写爬虫,爬取一页的数据需要重新发送一个请求的时候调用。这个类需要传递一些参数,其中比较常用的参数有:

1.url:这个request对象发送请求的url。

2.callback:在下载器下载完相应的数据后执行的回调函数。

3.method:请求的方法。默认为GET方法,可以设置为其他方法。

4.headers:请求头,对于一些固定的设置,放在settings.py中指定就可以了。对于那些非固定的,可以在发送请求的时候指定。

5.meta:比较常用。用于在不同的请求之间传递数据用的。

6.encoding:编码,默认的为utf-8,使用默认的就可以了

7.dot_filter:表示不由调度器过滤,在执行多次重复的请求的时候用得比较多。比如验证码。

8.errback:在发生错误的时候执行的函数

2.Response对象

Response对象一般是有scrapy给你自动构建的。因此开发者不需要关心如何创建response对象,而且如何使用他。response对象有很多属性,可以用来提取数据的。主要有一下属性

1.meta:从其他请求传过来的meta属性,可以用来保持多个请求之间的数据连接。

2.encoding:返回当前字符串编码和解码的格式

3.text:将返回的数据作为unicode字符串返回

4.body:将返回来的数据作为bytes字符串返回

5.xpath:xpath选择器

6.css:css选择器

发送POST请求:

如果需要post请求的话,就需要使用request的子类fromrequest来实现,如果想要在爬虫一开始的时候就发送给post请求的话,那么需要在爬虫类中重写start_requests(self)方法,并且不再调用start_urls里的url.

3.模拟登陆人人网

1.想发送post请求,那么推荐使用scrapy.FormRequest方法。可以方便的指定表单数据

2.如果想在爬虫一开始的时候就发送post请求,那么应该重写start_requests方法,发送请求

4.模拟登陆豆瓣
下载图片和文件

scrapy为下载item中包含的文件,提供了一个可重用的item pipelines。这写pipeline有些共同的方法和结构,我们称之为media pipeline。一般使用files pipeline或是images pipeline

好处:

1.避免重复下载过的文件

2.可以方便指定下载文件的存储路径

3.可以将下载的图片转换成通用的格式,比如png或是jpg

4.可以方便的生成缩量图

5.可以方便的检测图片的宽和高,确保他们满足最小限制

6.异步下载,效率非常高

下载文件的Files Pipeline:

使用Files Pipeline下载文件的话,按照一下步骤来完成

1.定义好一个Item,然后再这个item中定义两个属性,分别是file_urls以及files。file_urls是用来存储需要下载的文件的url链接,需要给一个列表。

2.当文件下载完成后,会把文件下载的相关信息存储到item的files属性中。比如下载路径,下载的url和文件的效验码等。

3.再配置文件settings.py中配置FILES_STORE,这个配置是用来设置文件下载下来的路径

4.启动pipeline:再ITEM_PIPELINES中设置scrapy.pipelines.files.FilesPipeline:1

下载图片的Images Pipeline:

但是用Images Pipeline下载文件的时候,按照一下步骤来完成:

1.定义好一个Item,然后再这个item中定义两个属性,分别为image_urls以及images。images_urls

是用来储存需要下载的图片的url链接,需要给一个列表。

2.当文件下载完成后,会把文件下载的相关信息存储到item的images属性中。比如下载路径、下载的url和图片的校验码等

3.再配置文件settings.py中配置IMAGES_STORE,这个配置是用来设置图片下载下来的路径

4.启动pipeline:在ITEM_PIPELINES中设置scrapy.pipelines.images.ImagesPipeline:1

下载器中间件:
Downloader Middlewares:

下载器中间件是引擎和下载器之间通信的中间将。在这个中间件中。我们可以设置代理,更换请求头等来达到反发爬虫的目的。要写中间器,可以在下载器中实现两个方法。一个是process_request(self,request,spider),这个方法是在请求发送之前会执行的,还有一个是process_response(self,request,reponse,spider),这个方法是数据下载到引擎之前执行。

process_request(self,request,spider):

这个方法是下载器在发送请求之前会执行的。一般可以在这个里面设置一些随机代理ip

1.参数:

​ 。request:发送请求request对象

​ 。spider:发送请求的spider对象

2.返回值:

​ 。返回None:如果返回None,Scrapy将继续处理该request,执行其他中间件中的相应方法,知道合适的下载器处理函数被调用。

​ 。返回Response对象:Scrapy将不会调用任何其他的process_request方法,将直接返回这个response对象。已经激活的中间件process_reponse()方法则会在每个response返回时被调用。

​ 。 返回Request对象:不再使用之前的request对象去下载数据,而是使用现在的request对象返回数据

​ 。如果这个方法抛出异常,则会调用process_exception方法。

process_response(self,request,spider):

1.参数:

​ 。request:request对象

​ 。response: response对象

​ 。spider:spider对象

2.返回值:

​ 。返回Response对象:会将这个新的response对象传给其他中间件,最终传给爬虫

​ 。 返回Request对象:下载器链被切断,返回的request会重新被下载器调度下载

​ 。如果这个方法抛出异常,则会调用request的errback方法,如果没有指定这个方法,就会抛出一个异常

随机请求头:

如果一直都是用一个请求头,那么可能会被服务器抓到的。所以就要用到很多的请求头。

http://www.useragentstring.com/pages/useragentstring.php

这个网址上面的有许多请求头,而且都是比较新的!舒服

代理ip

建议就是芝麻代理。

6. 分布式爬虫

scrapy 是一个框架,但是本身就不支持分布式的,就是要加上scrapy-redis

Advantage:
1.可以充分利用多台机器的带宽
2.可以充分利用多台机器的ip地址
3.多台机器做,爬取效率高。

Problem:
1.分布式爬虫是好多台机器再同时运行,如何保证不同的机器爬取亚眠的时候不会出现重复爬取的问题。
2.同样,分布式爬虫在不同的机器运行,在把数据爬完后如何保存在同一个地方。

Redis

redis是一种支持分布式的nosql数据库,是非关系型数据库,同时的保存在内存当中,同时redis可以定时把内存数据同步到磁盘,既可以将数据持久化.比memcached支持更多的数据结构

1. 启动redis:

sudo service redis-server start

2.连接上redis-server

redus-cli -h [ip] -p [端口]

3.添加

set key value

eg:set username xiaotou

将字符串值value关联到key。如果key已经持有其他值,set命令就复写旧值,无视其类型。并且默认的时期时间是永久,即永远不会过期。

4.删除:

del key

eg:del username

5.设置过期时间:

expire key timeout  (秒)

6.列表操作:

  1. 在列表的左边添加元素:
lpush key value

​将值value插入到列表key的表头中,如果key不存在,一个空列表会被创建并执行lpush操作。当key存在当不是列表类型是,将返回一个错误.

  1. 在列表右边添加元素:
lpush key value

​将值value插入到列表key的表尾。如果key不存在,一个空列表会被创建并执行rpush的操作。当key存在当不是列表类型是,返回一个错误。

  1. 查看列表中的元素
lrange key start stop

返回列表key中指定区间内的元素,区间以偏移量start和stop指定
如果要左边的第一个到最后一个lrange key 0-1, 0是第一个。-1是最后一个

  1. 移除列表中的元素:

​1)移除并返回列表key的头元素

lpop key

​2)移除并返回列表的尾元素

rpop key

​3)移除并返回列表的中的元素

lrem key count value

​将删除key这个列表中,count个值为value
​4)指定返回第几个元素

lindex key index

将返回key这个列表中索引index这个元素

​ 5)获取列表中的元素个数

llen key

eg:llen langueage
6)删除指定元素

lrem key count value
eg: lrem languages 0 php

根据参数count的值,移除列表中与参数value相等的元素。count的值可以是一下几种
count>0:从表头开始向表尾搜索,移除与value相等的元素,数量是count
count<0:从表尾开始先表头搜索,移除与value相等的元素,数量为count的绝对值
count=0:移除表中所有与value相等的值

7.set集合操作

1.添加元素

sadd set value1 value2
eg: sadd team xiaotuo datuo

2.查看元素

smembers set
eg: smember set

3.移除元素

srem set member...
eg : srem team xiaotuo datuo

4.查看集合中的元素个数

scard set
eg:scard teaml

5.获取多个集合的交集

sinter set1 set2
eg: sinter team1 team2

6.获取多个集合的并集

sunion set1 set2
eg:sunion team1 team2

7.获取多个集合的差集

sdiff set1 set2
eg:sdiff team1 team2

8.hash哈希操作

redis中的字典。
1.添加新值

hset key field value
eg:hset website baidu baidu.com

2.获取哈希中的field对应的值

hget key field
eg:hget website baidu

3.删除field中的某个field

hdel key field
eg:hdel website baidu

4.获取某个哈希中所有的field和value

hgetall key
eg:hgetall website 

5.获取某个哈希中所有的值

hvals key
eg:hvals website

6.判断哈希中是否存在某个field

hexists key field
eg:hexists website baidu

7.获取哈希中总共的键值对

hlen field
eg:hlen website
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小生凡一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值