大家好,我是小焦。今天给大家带来的是西西电影网的分布式爬虫。一直想着练习一下分布式爬虫,百般思量下也是想到百度云电影资源。百度之下无意中发现这个西西电影网上面有着大量的电影资源。虽说普通的爬虫就能搞定我们的需求,但是我们要假象有着大量的资源去爬取,所以我们以分布式爬虫的思路来进行项目。
分布式爬虫当然首选scrapy框架,省去大量的步骤。废话不多说,开始简单分析本次的项目吧。
准备工作
- 目标网址:www.xidianying.com
- 工具:python3、scrapy、scrapy-redis、redis、mongodb
这里我们先不说分布式怎么实现,先说说如何编写此次的爬虫的思路。先来看看目标网站的结构。
经过网站的分析,我们发现目标网站结构也是非常的简单,静态网址。内容方面也是非常的规整,现在我们可以开始编写代码了。我们使用python的scrapy爬虫框架来爬取。项目中小焦编写了两个spider,但是在测试分布式时出现了问题,随后又重新整顿了下代码,成功实现分布式,所以我们按照重新编写的代码来说。(对scrapy不了解的朋友请先复习一下该框架再阅读此文章)
# 创建爬虫项目
scrapy startproject dianying
# 创建爬虫,名字为xixi
scrapy genspider xixi www.xidianying.com
下面代码小焦就不展开讲了,简单说下思路。此次代码我的目标是爬取前10页的资源,因为分布式爬虫的原因,我们先重构start_requests函数,项目会自动调取该函数生成的链接,再而调取parse函数。parse()函数则是对目标网页,所有电影资源二级页面链接的提取,并调用parse_onepage()函数对二级页面的内容进行提取。列出代码,大家一看就知道怎么回事了。
import scrapy
from dianying.items import DianyingItem
class XixiSpider(scrapy.Spider):
name = 'xixi'
allowed_domains = ['www.xidianying.com']
# start_urls = ['http://www.xidianying.com/']
# 这块构建url链接
url = 'http://www.xidianying.com/list-56-{}.html'
# 重构start-request函数,scrapy调用时是从这里读取链接
def start_requests(self):
for i in range(1,11):
yield scrapy.Request(self.url.format(str(i)),callback=self.parse)
def parse(self, response):
print('开始爬取')
# 分析网页,找出所有的链接
lists = response.xpath("//tbody[starts-with(@id,'normalthread')]")
for list in lists:
b = '百度云'
# 获取所有的标题和网址
print('获取标题')
lname = list.xpath("./tr/th/a[2]/text()").extract()
# 返回的结果是list,我们转化为str格式
names = ''.join(lname)
print('标题为:',names)
# 筛选出百度云关键字的链接,如果标题中含有百度云三个字,则提取herf
if b in names:
lurl = list.xpath("./tr/th/a[2]/@href").extract()
# 同上进行结果是list,转换为str格式
urls = ''.join(lurl)
print("资源网址为:",urls)
yield scrapy.Request(urls,callback=self.parse_onepage)
# 这个函数为资源页面的百度云链接和提取码的分析
def parse_onepage(self,response):
item = DianyingItem()
# 获取目标网页中的href,有可能包含多个href,且返回结果为list了,所以我们进行遍历
print('获取页面中的所有链接')
lists = response.xpath("//td[@class='t_f']//a/@href").extract()
for list in lists:
if 'baidu.com' in list:
# 这块转换str是因为如果是多个a标签的话,list是lxml的unicode对象,所以先进行转换
item['baiduurl'] = str(list)
# 获取页面中的所有文本,找到提取码
all = response.xpath("//td[@class='t_f']//text()").extract()
for i in all:
a = '提取'
if a in i:
item['tiquma'] = i
# 获取该链接的标题
name = response.xpath("//span[@id='thread_subject']/text()").extract_first()
item['name'] = name
yield item
分布式爬虫
上面我们已经理出了爬虫的具体代码,现在说说分布式爬虫。其实也是非常的简单,就是所有的爬虫共享同一个队列。将同一个项目分配给所有的机器共同执行,从而达到众人拾柴火焰高的功效。而scrapy框架中,我们只需将调度器用redis数据库来代替即可,所以这里就需要使用到scrapy_redis这个库。为了达到去重的目的,借助了redis集合的去重功能。这里我们也就不细说了,具体的请自行百度用法,而scrapy框架中实现分布式,只需加入一下代码即可。
# 分布式爬虫配置,在setting文件中加入一下代码
# 首先将调度器和去重类替换为scrapy_redis提供的类,下面两个为核心配置
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# Redis连接设置,这里是本地数据库
REDIS_HOST = "192.168.31.214"
REDIS_PORT = 6379
# mongodb链接地址和db
MONGO_URI = '192.168.31.214'
MONGO_DATABASE = 'scrapy'
效果图
上面我们已经将整个目标网站的数据使用分布式进行爬取,并且保存到mongodb数据库中,对于pipelines文件数据操作这块也没有详细解说,这些大伙可自行下去了解,或者看小焦的代码即可。感谢阅读。
评论抢沙发