小白进阶之 Scrapy 第三篇(基于 Scrapy-Redis 的分布式以及 cookies 池)

举报
崔庆才丨静觅 发表于 2021/05/22 02:14:58 2021/05/22
【摘要】 啥话都不说了、进入正题。 首先我们更新一下 scrapy 版本。最新版为 1.3 再说一遍 Windows 的小伙伴儿 pip 是装不上 Scrapy 的。推荐使用 anaconda 、不然还是老老实实用 Linux 吧 123 conda install scrapy==1.3或者pip install scrapy==1.3 安装 Scrapy-R...

啥话都不说了、进入正题。 QQ图片20170205084843 首先我们更新一下 scrapy 版本。最新版为 1.3 再说一遍 Windows 的小伙伴儿 pip 是装不上 Scrapy 的。推荐使用 anaconda 、不然还是老老实实用 Linux 吧

1
2
3
conda install scrapy==1.3
或者
pip install scrapy==1.3

安装 Scrapy-Redis

1
2
3
conda install scrapy-redis
或者
pip install scrapy-redis

需要注意: Python 版本为 2.7,3.4 或者 3.5 。个人使用 3.6 版本也没有问题 Redis>=2.8 Scrapy>=1.0 Redis-py>=2.1 。 3.X 版本的 Python 都是自带 Redis-py 其余小伙伴如果没有的话、自己 pip 安装一下。 开始搞事! 开始之前我们得知道 scrapy-redis 的一些配置:PS 这些配置是写在 Scrapy 项目的 settings.py 中的!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#启用Redis调度存储请求队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

#确保所有的爬虫通过Redis去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

#默认请求序列化使用的是pickle 但是我们可以更改为其他类似的。PS:这玩意儿2.X的可以用。3.X的不能用
#SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"

#不清除Redis队列、这样可以暂停/恢复 爬取
#SCHEDULER_PERSIST = True

#使用优先级调度请求队列 (默认使用)
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
#可选用的其它队列
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'

#最大空闲时间防止分布式爬虫因为等待而关闭
#这只有当上面设置的队列类是SpiderQueue或SpiderStack时才有效
#并且当您的蜘蛛首次启动时,也可能会阻止同一时间启动(由于队列为空)
#SCHEDULER_IDLE_BEFORE_CLOSE = 10

#将清除的项目在redis进行处理
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}

#序列化项目管道作为redis Key存储
#REDIS_ITEMS_KEY = '%(spider)s:items'

#默认使用ScrapyJSONEncoder进行项目序列化
#You can use any importable path to a callable object.
#REDIS_ITEMS_SERIALIZER = 'json.dumps'

#指定连接到redis时使用的端口和地址(可选)
#REDIS_HOST = 'localhost'
#REDIS_PORT = 6379

#指定用于连接redis的URL(可选)
#如果设置此项,则此项优先级高于设置的REDIS_HOST 和 REDIS_PORT
#REDIS_URL = 'redis://user:pass@hostname:9001'

#自定义的redis参数(连接超时之类的)
#REDIS_PARAMS = {}

#自定义redis客户端类
#REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'

#如果为True,则使用redis的'spop'进行操作。
#如果需要避免起始网址列表出现重复,这个选项非常有用。开启此选项urls必须通过sadd添加,否则会出现类型错误。
#REDIS_START_URLS_AS_SET = False

#RedisSpider和RedisCrawlSpider默认 start_usls 键
#REDIS_START_URLS_KEY = '%(name)s:start_urls'

#设置redis使用utf-8之外的编码
#REDIS_ENCODING = 'latin1'

请各位小伙伴儿自行挑选需要的配置写到项目的 settings.py 文件中 英语渣靠 Google、看不下去的小伙伴儿看这儿:http://scrapy-redis.readthedocs.io/en/stable/readme.html 继续在我们上一篇博文中的爬虫程序修改: 首先把我们需要的 redis 配置文件写入 settings.py 中: 如果你的 redis 数据库按照前一片博文配置过则需要以下至少三项

1
2
3
4
5
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

REDIS_URL = 'redis://root:密码@主机IP:端口'

第三项请按照你的实际情况配置。 Nice 配置文件写到这儿。我们来做一些基本的反爬虫设置 最基本的一个切换 UserAgent! 首先在项目文件中新建一个 useragent.py 用来写一堆 User-Agent(可以去网上找更多,也可以用下面这些现成的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
agents = [
"Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5",
"Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7",
"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7",
"Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10",
"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)",
"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB5",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)",
"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110622 Firefox/6.0a2",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b4pre) Gecko/20100815 Minefield/4.0b4pre",
"Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0 )",
"Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)",
"Mozilla/5.0 (Windows; U; Windows XP) Gecko MultiZilla/1.6.1.0a",
"Mozilla/2.02E (Win95; U)",
"Mozilla/3.01Gold (Win95; I)",
"Mozilla/4.8 [en] (Windows NT 5.1; U)",
"Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko Netscape/7.1 (ax)",
"HTC_Dream Mozilla/5.0 (Linux; U; Android 1.5; en-ca; Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.2; U; de-DE) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.40.1 Safari/534.6 TouchPad/1.0",
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; sdk Build/CUPCAKE) AppleWebkit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; htc_bahamas Build/CRB17) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 1.5; de-ch; HTC Hero Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; HTC Legend Build/cupcake) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 1.5; de-de; HTC Magic Build/PLAT-RC33) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 FirePHP/0.3",
"Mozilla/5.0 (Linux; U; Android 1.6; en-us; HTC_TATTOO_A3288 Build/DRC79) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; T-Mobile G1 Build/CRB43) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari 525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.5; en-gb; T-Mobile_G2_Touch Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.0.1; de-de; Milestone Build/SHOLS_U2_01.14.0) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522 (KHTML, like Gecko) Safari/419.3",
"Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-ca; GT-P1000M Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 3.0.1; fr-fr; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 1.6; es-es; SonyEricssonX10i Build/R1FA016) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.6; en-us; SonyEricssonX10i Build/R1AA056) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
]

现在我们来重写一下 Scrapy 的下载中间件(哇靠!!重写中间件 好高端啊!!会不会好难!!!放心!!!So Easy!!跟我做!包教包会,毕竟不会你也不能顺着网线来打我啊): 关于重写中间件的详细情况 请参考 官方文档:http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/downloader-middleware.html#scrapy.contrib.downloadermiddleware.DownloaderMiddleware 在项目中新建一个 middlewares.py 的文件(如果你使用的新版本的 Scrapy,在新建的时候会有这么一个文件,直接用就好了) 首先导入 UserAgentMiddleware 毕竟我们要重写它啊!

1
2
3
4
5
6
import json ##处理json的包
import redis #Python操作redis的包
import random #随机选择
from .useragent import agents #导入前面的
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware #UserAegent中间件
from scrapy.downloadermiddlewares.retry import RetryMiddleware #重试中间件

开写:

1
2
3
4
5
class UserAgentmiddleware(UserAgentMiddleware):

def process_request(self, request, spider):
agent = random.choice(agents)
request.headers["User-Agent"] = agent

第一行:定义了一个类 UserAgentmiddleware 继承自 UserAgentMiddleware 第二行:定义了函数 process_request(request, spider) 为什么定义这个函数,因为 Scrapy 每一个 request 通过中间 件都会调用这个方法。 QQ20170206-223156 第三行:随机选择一个 User-Agent 第四行:设置 request 的 User-Agent 为我们随机的 User-Agent ^_^Y (^o^) Y 一个中间件写完了!哈哈 是不是 So easy! 下面就需要登陆了。这次我们不用上一篇博文的 FromRequest 来实现登陆了。我们来使用 Cookie 登陆。这样的话我们需要重写 Cookie 中间件!分布式爬虫啊!你不能手动的给每个 Spider 写一个 Cookie 吧。而且你还不会知道这个 Cookie 到底有没有失效。所以我们需要维护一个 Cookie 池 (这个 cookie 池用 redis)。 好!来理一理思路,维护一个 Cookie 池最基本需要具备些什么功能呢?

  1. 获取 Cookie
  2. 更新 Cookie
  3. 删除 Cookie
  4. 判断 Cookie 是否可用进行相对应的操作(比如重试)

好,我们先做前三个对 Cookie 进行操作。 首先我们在项目中新建一个 cookies.py 的文件用来写我们需要对 Cookie 进行的操作。 haoduofuli/haoduofuli/cookies.py: 首先日常导入我们需要的文件:

1
2
3
4
5
import requests
import json
import redis
import logging
from .settings import REDIS_URL ##获取settings.py中的REDIS_URL

首先我们把登陆用的账号密码 以 Key:value 的形式存入 redis 数据库。不推荐使用 db0(这是 Scrapy-redis 默认使用的,账号密码单独使用一个 db 进行存储。) QQ20170207-221128@2x 就像这个样子。 解决第一个问题:获取 Cookie:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
import json
import redis
import logging
from .settings import REDIS_URL

logger = logging.getLogger(__name__)
##使用REDIS_URL链接Redis数据库, deconde_responses=True这个参数必须要,数据会变成byte形式 完全没法用
reds = redis.Redis.from_url(REDIS_URL, db=2, decode_responses=True)
login_url = 'http://haoduofuli.pw/wp-login.php'

##获取Cookie
def get_cookie(account, password):
s = requests.Session()
payload = {
'log': account,
'pwd': password,
'rememberme': "forever",
'wp-submit': "登录",
'redirect_to': "http://http://www.haoduofuli.pw/wp-admin/",
'testcookie': "1"
}
response = s.post(login_url, data=payload)
cookies = response.cookies.get_dict()
logger.warning("获取Cookie成功!(账号为:%s)" % account)
return json.dumps(cookies)

这段很好懂吧。 使用 requests 模块提交表单登陆获得 Cookie,返回一个通过 Json 序列化后的 Cookie(如果不序列化,存入 Redis 后会变成 Plain Text 格式的,后面取出来 Cookie 就没法用啦。) 第二个问题:将 Cookie 写入 Redis 数据库(分布式呀,当然得要其它其它 Spider 也能使用这个 Cookie 了)

1
2
3
4
5
6
7
def init_cookie(red, spidername):
redkeys = reds.keys()
for user in redkeys:
password = reds.get(user)
if red.get("%s:Cookies:%s--%s" % (spidername, user, password)) is None:
cookie = get_cookie(user, password)
red.set("%s:Cookies:%s--%s"% (spidername, user, password), cookie)

使用我们上面建立的 redis 链接获取 redis db2 中的所有 Key (我们设置为账号的哦!),再从 redis 中获取所有的 Value (我设成了密码哦!) 判断这个 spider 和账号的 Cookie 是否存在,不存在 则调用 get_cookie 函数传入从 redis 中获取到的账号密码的 cookie; 保存进 redis,Key 为 spider 名字和账号密码,value 为 cookie。 这儿操作 redis 的不是上面建立的那个 reds 链接哦!而是 red; 后面会传进来的 (因为要操作两个不同的 db, 我在文档中没有看到切换 db 的方法,只好这么用了,知道的小伙伴儿留言一下)。 spidername 获取方式后面也会说的。 还有剩余的更新 Cookie 删除无法使用的账号等,大家伙可以自己试着写写(写不出来也没关系 不影响正常使用) 好啦!搞定!简直 So Easy!!!! 现在开始大业了!重写 cookie 中间件;估摸着吧!聪明的小伙儿看了上面重写 User-Agent 的方法,十之八九也知道怎么重写 Cookie 中间件了。 好啦,现在继续写 middlewares.py 啦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CookieMiddleware(RetryMiddleware):

def __init__(self, settings, crawler):
RetryMiddleware.__init__(self, settings)
self.rconn = redis.from_url(settings['REDIS_URL'], db=1, decode_responses=True)##decode_responses设置取出的编码为str
init_cookie(self.rconn, crawler.spider.name)

@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings, crawler)

def process_request(self, request, spider):
redisKeys = self.rconn.keys()
while len(redisKeys) > 0:
elem = random.choice(redisKeys)
if spider.name + ':Cookies' in elem:
cookie = json.loads(self.rconn.get(elem))
request.cookies = cookie
request.meta["accountText"] = elem.split("Cookies:")[-1]
break

第一行:不说 第二行第三行得说一下 这玩意儿叫重载(我想了大半天都没想起来叫啥,还是问了大才。尴尬)有啥用呢: 也不扯啥子高深问题了,小伙伴儿可能发现,当你继承父类之后;子类是不能用 def init() 方法的,不过重载父类之后就能用啦! 第四行:settings [‘REDIS_URL’] 是个什么鬼?这是访问 scrapy 的 settings。怎么访问的?下面说 第五行:往 redis 中添加 cookie。第二个参数就是 spidername 的获取方法(其实就是字典啦!)

1
2
3
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings, crawler)

这个貌似不好理解,作用看下面: D9DF3655-F28A-482C-8B02-C53B152958A0 这样是不是一下就知道了?? 至于访问 settings 的方法官方文档给出了详细的方法: http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/settings.html#how-to-access-settings QQ20170207-233701@2x 下面就是完整的 middlewares.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# -*- coding: utf-8 -*-

# Define here the models for your spider middleware
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/spider-middleware.html

from scrapy import signals
import json
import redis
import random
from .useragent import agents
from .cookies import init_cookie, remove_cookie, update_cookie
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
from scrapy.downloadermiddlewares.retry import RetryMiddleware
import logging


logger = logging.getLogger(__name__)

class UserAgentmiddleware(UserAgentMiddleware):

def process_request(self, request, spider):
agent = random.choice(agents)
request.headers["User-Agent"] = agent


class CookieMiddleware(RetryMiddleware):

def __init__(self, settings, crawler):
RetryMiddleware.__init__(self, settings)
self.rconn = redis.from_url(settings['REDIS_URL'], db=1, decode_responses=True)##decode_responses设置取出的编码为str
init_cookie(self.rconn, crawler.spider.name)

@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings, crawler)

def process_request(self, request, spider):
redisKeys = self.rconn.keys()
while len(redisKeys) > 0:
elem = random.choice(redisKeys)
if spider.name + ':Cookies' in elem:
cookie = json.loads(self.rconn.get(elem))
request.cookies = cookie
request.meta["accountText"] = elem.split("Cookies:")[-1]
break
#else:
#redisKeys.remove(elem)

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

#"""
#下面的我删了,各位小伙伴可以尝试以下完成后面的工作

#你需要在这个位置判断cookie是否失效

#然后进行相应的操作,比如更新cookie 删除不能用的账号

#写不出也没关系,不影响程序正常使用,

#"""

存储我也不写啦!就是这么简单一个分布式的 scrapy 就这么完成啦!!! 我试了下 三台机器 两个小时 就把整个站点全部爬完了。 弄好你的存储 放在不同的机器上就可以跑啦! 完整的代码在 GitHub 上: GitHub:https://github.com/thsheep/haoduofuli Y (^o^) Y 完工 下篇博文来对付爬虫的大敌:Ajax 以后的教程用微博做靶子,那些数据比较有用,可以玩玩分析什么的。

文章来源: cuiqingcai.com,作者:哎哟卧槽,版权归原作者所有,如需转载,请联系作者。

原文链接:cuiqingcai.com/4048.html

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200