目录
Scrapy架构图(Scrapy 使用了 Twisted异步网络库来处理网络通讯):
Downloader Middlewares (下载器中间件)
process_request(self, request, spider)
process_response(self, request, response, spider)
Scrapy框架
Scrapy框架介绍:
写一个爬虫,需要做很多的事情。比如:发送网络请求、数据解析、数据存储、反反爬虫机制(更换ip代理、设置请求头等)、异步请求等。这些工作如果每次都要自己从零开始写的话,比较浪费时间。因此Scrapy
把一些基础的东西封装好了,在他上面写爬虫可以变的更加的高效(爬取效率和开发效率)。因此真正在公司里,一些上了量的爬虫,都是使用Scrapy
框架来解决。
Scrapy架构图(Scrapy 使用了 Twisted异步网络库来处理网络通讯):
流程图(1):
流程图(2):
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交给调度器等待抓取
安装和文档:
- 安装:通过
pip install scrapy
即可安装。 - Scrapy官方文档:http://doc.scrapy.org/en/latest
- Scrapy中文文档:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html
注意:
- 在
ubuntu
上安装scrapy
之前,需要先安装以下依赖:sudo apt-get install python3-dev build-essential python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
,然后再通过pip install scrapy
安装。- 如果在
windows
系统下,提示这个错误ModuleNotFoundError: No module named 'win32api'
,那么使用以下命令可以解决:pip install pypiwin32
。
快速入门:
创建项目:
要使用Scrapy
框架创建项目,需要通过命令来创建。首先进入到你想把这个项目存放的目录。然后使用以下命令创建:
scrapy startproject [项目名称]
目录结构介绍:
以下介绍下主要文件的作用:
- items.py:用来存放爬虫爬取下来数据的模型。
- middlewares.py:用来存放各种中间件的文件。
- pipelines.py:用来将
items
的模型存储到本地磁盘中。 - settings.py:爬虫的一些配置信息(比如请求头、多久发送一次请求、ip代理池等)。
- scrapy.cfg:项目的配置文件。
-
spiders包:以后所有的爬虫,都是存放到这个里面。
使用Scrapy框架爬取糗事百科段子项目
使用命令创建一个爬虫:
scrapy genspider qsbk "qiushibaike.com"
创建了一个名字叫做qsbk
的爬虫,并且能爬取的网页只会限制在qiushibaike.com
这个域名下。
爬虫代码解析:
import scrapy
class QsbkSpider(scrapy.Spider):
name = 'qsbk'
allowed_domains = ['qiushibaike.com']
start_urls = ['http://qiushibaike.com/']
def parse(self, response):
pass
其实这些代码我们完全可以自己手动去写,而不用命令。只不过是不用命令,自己写这些代码比较麻烦。
要创建一个Spider,那么必须自定义一个类,继承自scrapy.Spider
,然后在这个类中定义三个属性和一个方法。
- name:这个爬虫的名字,名字必须是唯一的。
- allow_domains:允许的域名。爬虫只会爬取这个域名下的网页,其他不是这个域名下的网页会被自动忽略。
- start_urls:爬虫从这个变量中的url开始。
- parse:引擎会把下载器下载回来的数据扔给爬虫解析,爬虫再把数据传给这个
parse
方法。这个是个固定的写法。这个方法的作用有两个,第一个是提取想要的数据。第二个是生成下一个请求的url。
修改settings.py
代码:
在做一个爬虫之前,一定要记得修改setttings.py
中的设置。两个地方是强烈建议设置的。
ROBOTSTXT_OBEY
设置为False。默认是True。即遵守机器协议,那么在爬虫的时候,scrapy首先去找robots.txt文件,如果没有找到。则直接停止爬取。DEFAULT_REQUEST_HEADERS
添加User-Agent
。这个也是告诉服务器,我这个请求是一个正常的请求,不是一个爬虫。
完成的爬虫代码:
-
爬虫部分代码:
import scrapy from abcspider.items import QsbkItem class QsbkSpider(scrapy.Spider): name = 'qsbk' allowed_domains = ['qiushibaike.com'] start_urls = ['https://www.qiushibaike.com/text/'] def parse(self, response): outerbox = response.xpath("//div[@id='content-left']/div") items = [] for box in outerbox: author = box.xpath(".//div[contains(@class,'author')]//h2/text()").extract_first().strip() content = box.xpath(".//div[@class='content']/span/text()").extract_first().strip() item = QsbkItem() item["author"] = author item["content"] = content items.append(item) return items
-
items.py部分代码:
import scrapy class QsbkItem(scrapy.Item): author = scrapy.Field() content = scrapy.Field()
-
pipeline部分代码:
import json class AbcspiderPipeline(object): def __init__(self): self.items = [] def process_item(self, item, spider): self.items.append(dict(item)) print("="*40) return item def close_spider(self,spider): with open('qsbk.json','w',encoding='utf-8') as fp: json.dump(self.items,fp,ensure_ascii=False)
settings.py中要把 ITEM_PIPELINES 打开
'qsbk.pipelines.QsbkPipeline': 300, #300代表pipeline的优先级,值越小,优先级越高
运行scrapy项目:
运行scrapy项目。需要在终端,进入项目所在的路径,然后scrapy crawl [爬虫名字]
即可运行指定的爬虫。如果不想每次都在命令行中运行,那么可以把这个命令写在一个文件中。以后就在pycharm中执行运行这个文件就可以了。比如现在工程的根目录新创建一个文件叫做start.py
,然后在这个文件中填入以下代码:
from scrapy import cmdline
cmdline.execute("scrapy crawl qsbk".split())
糗事百科Scrapy爬虫项目
总结:
一、创建项目和爬虫:
- 创建项目:‘scrapy startproject [爬虫名字]’。
- 创建爬虫:进入到项目 所在的路径,执行命令:`scrapy genspider [ 爬虫名字] [ 爬虫的域名]`。注意,爬虫名字不能和项目名一样。
二、糗事百科Scrapy爬虫笔记:
- responst是一个`scrapy.http.response.html.HtmlResponse`对象。可以执行`xpath`和`css`语法来提取数据。
- 提取出来的数据,是一个`Selector`或者是一个`SelectorList`对象。如果想要获取其中的字符串,那么应该 执行`getall`或者`get`方法。
- getall方法:获取`Selector`中的所有文本。返回的是一个列表。等同于extract方法。
- get方法:获取的是`Selector`中的第一个文本。返回的是一个str类型。等同于extract_first方法。
- 如果数据解析回来,要传给pipline处理。那么可以使用`yield`来返回 。或者是收集所有的item,最后统一使用return返回。
- item:建议在`items.py`中定义好模型,以后就不要使用字典。
- pipeline:这个是专门用来保存数据的。其中有三个方法是会经常用的。
*`open_spider(self,spider)`:当爬虫被打开的时候执行。
*`process_item(self,item,spider)`:当爬虫有item传过来的时候会被调用,一般用来保存数据。
*`close_spider(self,spider)`:当爬虫关闭的时候会被调用。
要激活piplilne,应该在`settings.py`中,设置`ITEM_PIPELINES`示例如下:
ITEM_PIPELINES = {
'qsbk.pipelines.QsbkPipeline': 300,
}
CrawlSpider
在上一个糗事百科的爬虫案例中。我们是自己在解析完整个页面后获取下一页的url,然后重新发送一个请求。有时候我们想要这样做,只要满足某个条件的url,都给我进行爬取。那么这时候我们就可以通过CrawlSpider
来帮我们完成了。CrawlSpider
继承自Spider
,只不过是在之前的基础之上增加了新的功能,可以定义爬取的url的规则,以后scrapy碰到满足条件的url都进行爬取,而不用手动的yield Request
。
创建CrawlSpider爬虫:
之前创建爬虫的方式是通过scrapy genspider [爬虫名字] [域名]
的方式创建的。如果想要创建CrawlSpider
爬虫,那么应该通过以下命令创建:
scrapy genspider -t crawl [爬虫名字] [域名]
LinkExtractors链接提取器:
使用LinkExtractors
可以不用程序员自己提取想要的url,然后发送请求。这些工作都可以交给LinkExtractors
,他会在所有爬的页面中找到满足规则的url
,实现自动的爬取。以下对LinkExtractors
类做一个简单的介绍:
class scrapy.linkextractors.LinkExtractor(
allow = (),
deny = (),
allow_domains = (),
deny_domains = (),
deny_extensions = None,
restrict_xpaths = (),
tags = ('a','area'),
attrs = ('href'),
canonicalize = True,
unique = True,
process_value = None
)
主要参数讲解:
- allow:允许的url。所有满足这个正则表达式的url都会被提取。
- deny:禁止的url。所有满足这个正则表达式的url都不会被提取。
- allow_domains:允许的域名。只有在这个里面指定的域名的url才会被提取。
- deny_domains:禁止的域名。所有在这个里面指定的域名的url都不会被提取。
- restrict_xpaths:严格的xpath。和allow共同过滤链接。
Rule规则类:
定义爬虫的规则类。以下对这个类做一个简单的介绍:
class scrapy.spiders.Rule(
link_extractor,
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案例
总结:
需要使用`LinkExtractor
`和`Rule`。这两个东西决定爬虫的具体走向。
- allow设置规则的方法:要能够限制在我们想要的url上面。不要跟其它url产生相同的正则表达式即可。
- 什么情况下使用follow:如果在爬取页面的时候,需要进满足当前条件的url再进行跟进,那么就设置为True。否则设置为Fash。
- 什么情况下该指定callback:如果这个url对应的页面,只是为了获取更多的url,并不需要里面的数据,那么可以不指定callback。如果想要获取url对应页面中的数据,那么就需要指定一个callback。
Scrapy Shell
我们想要在爬虫中使用xpath、beautifulsoup、正则表达式、css选择器等来提取想要的数据。但是因为scrapy
是一个比较重的框架。每次运行起来都要等待一段时间。因此要去验证我们写的提取规则是否正确,是一个比较麻烦的事情。因此Scrapy
提供了一个shell,用来方便的测试规则。当然也不仅仅局限于这一个功能。
打开Scrapy Shell:
打开终端,进入到Scrapy
项目所在的目录,然后进入到scrapy
框架所在的虚拟环境中,输入命令scrapy shell [链接]
。就会进入到scrapy的shell环境中。在这个环境中,你可以跟在爬虫的parse
方法中一样使用了。
总结:
- 可以方便我们做一些数据提取的测试代码。
- 如果想要执行scrapy命令,那么毫无疑问,肯定是要先进入到scrapy所在的环境中。
- 如果想要读取某个项目的配置信息,那么应该先进入到这个项目中,再执行`scrapy shell`命令。
Request和Response对象
Request对象:
Request对象在我们写爬虫,爬取一页的数据需要重新发送一个请求的时候调用。这个类需要传递一些参数,其中比较常用的参数有:
- url:这个request对象发送请求url。
- callback:在下载器下载完相应的数据后执行的回调函数。
- method:请求的方法。默认为GET方法,可以设置为其他方法。
- headers:请求头,对于一些固定的设置,放在settings.py中指定就可以了。对于那些非固定的,可以在发送请求的时候指定。
- meta:比较常用。用于在不同的请求之间 传递数据用的。
- encoding:编码。默认的为utf-8,使用默认的就可以了。
- dot_filter:表示不由调度器过滤。在执行多次重复的请求的时候用得比较多。
- errback:在发生错误的时候执行的函数。
Response对象:
Response对象一般是由Scrapy给你自动构建的。因些开发者不需要关心如何创建Response对象,而是如何使用他。Response对象有
很多属性,可以用来提取数据的。主要有以下属性:
- meta:从其他请求传过来的meta属性,可以用来保持多个请求之间 的数据连接。
- encoding:返回当前字符串编码和解码的格式。
- text:将返回来的数据作为unicode字符串返回。
- body:将返回来的数据作为bytes字符串返回。
- xpath:xpath选择器。
- css:css选择器。
发送POST请求:
有时候我们想在在请求数据的时候发送post请求,那么这时候需要使用Request的子类FormRequest来实现。如果想要在爬虫一开始
的时候就发送POST请求,那么需要在爬虫类中重写start_requests(delf)方法,并且不再调用 start_urls里的url。
模拟登录
案例一:模拟登录人人网
1、想要发送post请求,那么推荐使用`scrpay.FormRequest`方法。可以方便的指定表单数据。
2、如果想在爬虫一开始的时候就发送post请求,那么应该重写`start_requests`方法。在这个方法中,发送post请求。
案例二:模拟登录豆瓣网(识别验证码)
待完善
下载文件和图片
Scrapy为下载item中包含的文件(比如在攫取到产品时,同时也想保存对应的图片)提供了一个可重用的item pipelinses.
这些pipeline有些共同的方法和结构(我们称之为media pipeline)。一般来说你会使用Files Pipeline或者Images Pipelines。
为什么要选择使用scrapy内置的下载文件的方法
- 避免重新下载最近已经下载过的数据。
- 可以方便的指定文件存储的路径。
- 可以将下载的图片转换成通用的格式,比如png或者jpg.
- 可以方便生成缩略图。
- 可以方便的检测图片的宽和高,确保他们满足最小限制。
- 异步下载,效率非常高。
下载文件的 Files Pipeline:
当使用Files Pipeline 下载文件的时候,按照以下步骤来完成:
- 定义好一个Item,然后在这个item中定义两个属性,分别为file_urls以及files。file_urls是用来存储需要下载的图片的url链接,需要给一个列表。
- 当文件下载完成后,会把文件下载的相关信息存储到item的files属性中。比如下载路径、下载的url和文件的验证码等。
- 在配置文件settings.py中配置FILES_STORE,这个配置是用来设置文件下载下来的路径。
- 启动pipeline:在ITEM_PIPELINES中设置scrapy.pipelines.files.FilesPipeline:1。
下载图片的Images Pipeline:
当使用Images Pipeline下载图片的时候,按照以下步骤来完成:
- 定义好一个Item,然后在这个item中定义两个属性,分别为image_urls以及images。image_urls是用来存储需要下载的图片链接,需要给一个列表。
- 当文件下载完成后,会把文件下载的相关信息存储到item的images属性中。比如下载路径、下载的url和图片的验证码等。
- 在配置文件settings.py中配置IMAGES_STORE,这个配置是用来设置文件下载下来的路径。
- 启动pipeline:在ITEM_PIPELINES中设置scrapy.pipelines.images.ImagesPipeline:1。
汽车之家宝马5系高清图片下载实战
下载中间件
Downloader Middlewares (下载器中间件)
下载器中间件是引擎和下载器之间通信的中间件。在这个中间件中我们可以设置代理、更换请求头等来达到反反爬虫的目的,要写下载器中间件,可以在下载器中实现两个方法。一个是process_request(self, request, spider),这个方法会在请求发送之前执行,还有一个是process_response(self, request, response, spider),这个方法是数据下载到引擎之间执行。
process_request(self, request, spider)
这个方法是下载器在发送请求之前会执行的。一般可以在这里面设置随机代理ip等。
1、参数:
。request:发送请求的request对象。
。 spider:发送请求的spider对象。
2、返回值:
。 返回None:如果返回None,Scrapy将继续处理该request,执行其它 中间件中的相应方法,直到合适的下载器处理函数被调用。
。返回Response对象:Scrapy将不会调用任何其他的process_request方法,将直接返回response对象,已经激活中间件的process_response()方法则会在每个response返回时被调用。
。返回Request对象:不再使用之前的request对象去下载数据,而是根据现在返回的request对象返回数据。
。如果这个方法中抛出了异常,则会调用process_exception方法。
process_response(self, request, response, spider)
这个方法是下载器在发送请求之前会执行的。一般可以在这里面设置随机代理ip等。
1、参数:
。request:request对象。
。 response:被处理的response对象。
。spider:spider对象。
2、返回值:
。 返回Response:会将这个新的response对象传给其他中间件,最终传给爬虫。
。返回Response对象:下载器链接切断,返回response会重新被下载器调度下载。
。如果抛出一个异常,那么调用response的errback方法,如果没有指定这个方法,那么会抛出一个异常。
随机请求头中间件:
爬虫在频繁访问一个页面的时候,这个请求头如果一直保持一致。那么很容易被服务器发现,从面禁止掉这个请求头的访问,因此我们要在访问这个页面之前随机的更改请求头,这样才可以避免爬虫被抓。随机更改请求头,可以在下载器中间件中实现,在请求发送给服务器之前,随机选择一个请求头。这样就可以避免总傅一个请求头了。示例代码如下:
class UserAgentDownloadMiddleware(object):
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; Browzar)',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; MyIE2; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0)'
]
def process_request(self, request, spider):
user_agent = random.choice(self.USER_AGENTS)
request.headers['User-Agent'] = user_agent
user-agent列表网址:http://useragentstring.com/pages/useragentstring.php?typ=Browser
ip代理池中间件
购买代理:
在以下代理商中购买代理:
- 芝麻代理:http://www.zhimaruanjian.com/
- 太阳代理:http://www.taiyangruanjian.com/
- 快代理 :https://www.kuaidaili.com/
- 蚂蚁代理:http://www.mayidaili.com/
等购买代理。
使用ip代理池:
示例代码如下:
# 开放代理池设置
# class IPProxyDownloadMiddleware(object):
# PROXIES = [
# '171.41.81.164:9999',
# '171.41.81.253:9999',
# '171.41.81.96:9999',
# '171.41.81.93:9999',
# '112.85.171.65:9999',
# '117.114.149.66:53281'
# '106.12.217.43:8118'
#
# ]
#
# def process_request(self, request, spider):
# proxy = random.choice(self.PROXIES)
# request.meta['proxy'] = "http://" + proxy
# 独享代理池设置
class IPProxyDownloadMiddleware(object):
def process_request(self, request, spider):
proxy = '121.199.6.124:16816'
user_password = "970138074:rcdj35ur"
request.meta['proxy'] = "http://" + proxy
# bytes
b64_user_password = base64.b64encode(user_password.encode('utf-8'))
request.headers['Proxy-Authorization'] = 'Basic' + b64_user_password.decode('utf-8')
Scrapy爬虫实战
Boss直聘爬虫。
Boss直聘有很高的反爬虫机制,只要用同一个ip访问多个职位列表页,就会被封掉ip。采用代理ip方式可以解决问题。
简书网站整站爬虫。
- 数据保存到mysql数据库中。
- 将selenium+chromedriver集成到scrapy.
Scrapy-Redis分布式组件
redis数据库介绍:
概述
redis
是一种支持分布式的nosql
数据库,他的数据是保存在内存中,同时redis
可以定时把内存数据同步到磁盘,即可以将数据持久化,并且他比memcached
支持更多的数据结构(string
,list列表[队列和栈]
,set[集合]
,sorted set[有序集合]
,hash(hash表)
)。相关参考文档:http://redisdoc.com/index.html
redis使用场景:
- 登录会话存储:存储在
redis
中,与memcached
相比,数据不会丢失。 - 排行版/计数器:比如一些秀场类的项目,经常会有一些前多少名的主播排名。还有一些文章阅读量的技术,或者新浪微博的点赞数等。
- 作为消息队列:比如
celery
就是使用redis
作为中间人。 - 当前在线人数:还是之前的秀场例子,会显示当前系统有多少在线人数。
- 一些常用的数据缓存:比如我们的
BBS
论坛,板块不会经常变化的,但是每次访问首页都要从mysql
中获取,可以在redis
中缓存起来,不用每次请求数据库。 - 把前200篇文章缓存或者评论缓存:一般用户浏览网站,只会浏览前面一部分文章或者评论,那么可以把前面200篇文章和对应的评论缓存起来。用户访问超过的,就访问数据库,并且以后文章超过200篇,则把之前的文章删除。
- 好友关系:微博的好友关系使用
redis
实现。 - 发布和订阅功能:可以用来做聊天软件。
redis
和memcached
的比较:
memcached | redis | |
---|---|---|
类型 | 纯内存数据库 | 内存磁盘同步数据库 |
数据类型 | 在定义value时就要固定数据类型 | 不需要 |
虚拟内存 | 不支持 | 支持 |
过期策略 | 支持 | 支持 |
存储数据安全 | 不支持 | 可以将数据同步到dump.db中 |
灾难恢复 | 不支持 | 可以将磁盘中的数据恢复到内存中 |
分布式 | 支持 | 主从同步 |
订阅与发布 | 不支持 | 支持 |
redis
在ubuntu
系统中的安装与启动
- 安装:
sudo apt-get install redis-server
- 卸载:
sudo apt-get purge --auto-remove redis-server
-
启动:
redis
安装后,默认会自动启动,可以通过以下命令查看:ps aux|grep redis
如果想自己手动启动,可以通过以下命令进行启动:
sudo service redis-server start
-
停止:
sudo service redis-server stop
redis在windows系统中的安装与启动:
- 下载:redis官方是不支持windows操作系统的。但是微软的开源部门将redis移植到了windows上。因此下载地址不是在redis官网上。而是在github上:https://github.com/MicrosoftArchive/redis/releases。
- 安装:点击一顿下一步安装就可以了。
- 运行:进入到
redis
安装所在的路径然后执行redis-server.exe redis.windows.conf
就可以运行了。 - 连接:
redis
和mysql
以及mongo
是一样的,都提供了一个客户端进行连接。输入命令redis-cli
(前提是redis安装路径已经加入到环境变量中了)就可以连接到redis
服务器了。
其他机器访问本机redis服务器:
想要让其他机器访问本机的redis服务器。那么要修改redis.conf的配置文件,将bind改成bind [自己的ip地址或者0.0.0.0]
,其他机器才能访问。
注意:bind绑定的是本机网卡的ip地址,而不是想让其他机器连接的ip地址。如果有多块网卡,那么可以绑定多个网卡的ip地址。如果绑定到额是0.0.0.0,那么意味着其他机器可以通过本机所有的ip地址进行访问。
对redis
的操作
对redis
的操作可以用两种方式,第一种方式采用redis-cli
,第二种方式采用编程语言,比如Python
、PHP
和JAVA
等。
-
使用
redis-cli
对redis
进行字符串操作: -
启动
redis
:sudo service redis-server start
- 连接上
redis-server
:redis-cli -h [ip] -p [端口]
-
添加:
set key value 如: set username xiaotuo
将字符串值
value
关联到key
。如果key
已经持有其他值,set
命令就覆写旧值,无视其类型。并且默认的过期时间是永久,即永远不会过期。 -
删除:
del key 如: del username
-
设置过期时间:
expire key timeout(单位为秒)
也可以在设置值的时候,一同指定过期时间:
set key value EX timeout 或: setex key timeout value
-
查看过期时间:
ttl key 如: ttl username
-
查看当前
redis
中的所有key
:keys *
-
列表操作:
-
在列表左边添加元素:
lpush key value
将值
value
插入到列表key
的表头。如果key
不存在,一个空列表会被创建并执行lpush
操作。当key
存在但不是列表类型时,将返回一个错误。 -
在列表右边添加元素:
rpush key value
将值value插入到列表key的表尾。如果key不存在,一个空列表会被创建并执行RPUSH操作。当key存在但不是列表类型时,返回一个错误。
-
查看列表中的元素:
lrange key start stop
返回列表
key
中指定区间内的元素,区间以偏移量start
和stop
指定,如果要左边的第一个到最后的一个lrange key 0 -1
。 -
移除列表中的元素:
- 移除并返回列表
key
的头元素:lpop key
- 移除并返回列表的尾元素:
rpop key
-
移除并返回列表
key
的中间元素:lrem key count value
将删除
key
这个列表中,count
个值为value
的元素。
- 移除并返回列表
-
指定返回第几个元素:
lindex key index
将返回
key
这个列表中,索引为index
的这个元素。 -
获取列表中的元素个数:
llen key 如: llen languages
-
删除指定的元素:
lrem key count value 如: lrem languages 0 php
根据参数 count 的值,移除列表中与参数 value 相等的元素。
count
的值可以是以下几种:- count > 0:从表头开始向表尾搜索,移除与
value
相等的元素,数量为count
。 - count < 0:从表尾开始向表头搜索,移除与
value
相等的元素,数量为count
的绝对值。 - count = 0:移除表中所有与
value
相等的值。
- count > 0:从表头开始向表尾搜索,移除与
-
-
set
集合的操作:- 添加元素:
sadd set value1 value2.... 如: sadd team xiaotuo datuo
- 查看元素:
smembers set 如: smembers team
- 移除元素:
srem set member... 如: srem team xiaotuo datuo
- 查看集合中的元素个数:
scard set 如: scard team1
- 获取多个集合的交集:
sinter set1 set2 如: sinter team1 team2
- 获取多个集合的并集:
sunion set1 set2 如: sunion team1 team2
- 获取多个集合的差集:
sdiff set1 set2 如: sdiff team1 team2
- 添加元素:
-
hash
哈希操作:-
添加一个新值:
hset key field value 如: hset website baidu baidu.com
将哈希表
key
中的域field
的值设为value
。
如果key
不存在,一个新的哈希表被创建并进行HSET
操作。如果域field
已经存在于哈希表中,旧值将被覆盖。 -
获取哈希中的
field
对应的值:hget key field 如: hget website baidu
-
删除
field
中的某个field
:hdel key field 如: hdel website baidu
-
获取某个哈希中所有的
field
和value
:hgetall key 如: hgetall website
-
获取某个哈希中所有的
field
:hkeys key 如: hkeys website
-
获取某个哈希中所有的值:
hvals key 如: hvals website
-
判断哈希中是否存在某个
field
:hexists key field 如: hexists website baidu
-
获取哈希中总共的键值对:
hlen field 如: hlen website
-
-
事务操作:Redis事务可以一次执行多个命令,事务具有以下特征:
- 隔离操作:事务中的所有命令都会序列化、按顺序地执行,不会被其他命令打扰。
- 原子操作:事务中的命令要么全部被执行,要么全部都不执行。
-
开启一个事务:
multi
以后执行的所有命令,都在这个事务中执行的。
-
执行事务:
exec
会将在
multi
和exec
中的操作一并提交。 -
取消事务:
discard
会将
multi
后的所有命令取消。 -
监视一个或者多个
key
:watch key...
监视一个(或多个)key,如果在事务执行之前这个(或这些) key被其他命令所改动,那么事务将被打断。
-
取消所有
key
的监视:unwatch
-
发布/订阅操作:
- 给某个频道发布消息:
publish channel message
- 订阅某个频道的消息:
subscribe channel
- 给某个频道发布消息:
Scrapy-Redis分布式爬虫组件
Scrapy
是一个框架,他本身是不支持分布式的。如果我们想要做分布式的爬虫,就需要借助一个组件叫做Scrapy-Redis
,这个组件正是利用了Redis
可以分布式的功能,集成到Scrapy
框架中,使得爬虫可以进行分布式。可以充分的利用资源(多个ip、更多带宽、同步爬取)来提高爬虫的爬行效率。
分布式爬虫的优点:
- 可以充分利用多台机器的带宽。
- 可以充分利用多台机器的ip地址。
- 多台机器做,爬取效率更高。
分布式爬虫必须要解决的问题:
- 分布式爬虫是好几台机器在同时运行,如何保证不同的机器爬取页面的时候不会出现重复爬取的问题。
- 同样,分布式爬虫在不同的机器上运行,在把数据爬完后如何保证保存在同一个地方。
安装:
通过pip install scrapy-redis
即可安装。
Scrapy-Redis架构:
Scrapy架构图:
Scrapy-Redis架构图:
分布式爬虫架构图:
以上两个图片对比我们可以发现。Item Pipeline
在接收到数据后发送给了Redis
、Scheduler
调度器调度数据也是从Redis
中来的、并且其实数据去重也是在Redis
中做的。
编写Scrapy-Redis分布式爬虫:
要将一个Scrapy
项目变成一个Scrapy-redis
项目只需修改以下三点就可以了:
- 将爬虫的类从
scrapy.Spider
变成scrapy_redis.spiders.RedisSpider
;或者是从scrapy.CrawlSpider
变成scrapy_redis.spiders.RedisCrawlSpider
。 - 将爬虫中的
start_urls
删掉。增加一个redis_key="xxx"
。这个redis_key
是为了以后在redis
中控制爬虫启动的。爬虫的第一个url,就是在redis中通过这个发送出去的。 - 在配置文件中增加如下配置:
# Scrapy-Redis相关配置
# 确保request存储到redis中
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 确保所有爬虫共享相同的去重指纹
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 设置redis为item pipeline
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
# 在redis中保持scrapy-redis用到的队列,不会清理redis中的队列,从而可以实现暂停和恢复的功能。
SCHEDULER_PERSIST = True
# 设置连接redis信息
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
- 运行爬虫:
- 在爬虫服务器上。进入爬虫文件所在的路径,然后输入命令:
scrapy runspider [爬虫名字]
。 - 在
Redis
服务器上,推入一个开始的url链接:redis-cli> lpush [redis_key] start_url
开始爬取。
- 在爬虫服务器上。进入爬虫文件所在的路径,然后输入命令:
搜房网分布式爬虫项目
多台电脑的环境配置
1、获取当前项目所用到的包,pypiwin32==200属于win下的,linux没有,安装时记得删除。
pip3 freeze > requirements.txt
2、如果要在同一台机器上使用多个python版本,可以创建虚拟环境。
pwp@ubuntu:pip3 install virtualenvwrapper
pwp@ubuntu:fang_spider$ which python3
/usr/bin/python3
pwp@ubuntu:fang_spider$ mkvirtualenv -p /usr/bin/python3 crawler-env #创建名为crawler-env的虚拟环境
3、安装
pip3 install -r requirements.txt
4、ubuntu下RedisDesktopManager的安装,redis可视化工具
官方网站:https://redisdesktop.com/download
一句命令行解决:sudo snap install redis-desktop-manager