scrapy-redis實現分佈式爬蟲

OK!終於到了分佈式爬蟲了,說下,我整了幾天才把分佈式爬蟲給搞定。(內心苦哇)爲何會這麼久,請聽我徐徐道來。html

在使用分佈式爬蟲的時候通用的作法是一臺電腦做爲master端,另外的多臺電腦做爲slaver端,我採用的是主機與虛擬機來搭建的環境,說說個人主機,一臺聯想的y410筆記本,只有4G的內存,用到如今已經快5年了,還很堅挺 :-)就是內存小了點,個人虛擬機用的是xubuntu(輕量級的ubuntu),虛擬機做爲的master端,master端的redis用來存儲數據以及url去重,主機做爲slaver端執行代碼。這裏面有一步很關鍵,那就是個人主機(slaver端)要可以訪問個人虛擬機(master端)裏面的redis數據庫才行,很無奈我就是卡在了這裏,個人主機不管如何都沒法ping通虛擬機,也就是訪問不了xubuntu的redis數據庫,在網上找了各類解決方法,都行不通,最後沒辦法了直接卸載了vnware重裝以後,又修改了下網絡配置,才最終解決問題。實屬心酸~mysql

因此呀,若是有小夥伴碰見相似的問題,除了google以外,能夠直接考慮重裝下本身的vmware。redis

 

嗯~好,當主機與虛擬機ping通以後就能夠來作分佈式了,具體實現細節我就再也不贅餘了,百度一下出來一大堆結果。我以後會寫一篇關於scrapy-redis的源碼解讀的博客。這裏只是記錄一下具體代碼實現的過程。sql

目標網址:人民網
http://politics.people.com.cn/GB/1024/index1.html

 一樣無反爬措施,能夠安心使用。mongodb

items.py
 1 import scrapy
 2 
 3 
 4 class PeopleItem(scrapy.Item):
 5     # define the fields for your item here like:
 6     # name = scrapy.Field()
 7     title = scrapy.Field()
 8     pub_time = scrapy.Field()
 9     url = scrapy.Field()
10     content = scrapy.Field()
 spiders.py
 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 
 4 from scrapy_redis.spiders import RedisSpider
 5 from ..items import PeopleItem
 6 
 7 
 8 class RedisTestSpider(RedisSpider):
 9     name = 'redis-test'
10     # allowed_domains = ['people.com.cn']  有坑需注意
11     # start_urls = ['http://politics.people.com.cn/GB/1024/index1.html']
12 
13     redis_key = "redistest:start_urls"
14 
15     def __init__(self, *args, **kwargs):
16         domain = kwargs.pop('domain', '')
17         self.allowed_domains = filter(None, domain.split(','))
18         super(RedisTestSpider, self).__init__(*args, **kwargs)
19 
20     def parse(self, response):
21         news_list = response.xpath("//div[@class='ej_list_box clear']/ul/li")
22         for new in news_list:
23             item = PeopleItem()
24             title = new.xpath("./a/text()").extract_first()
25             url = new.xpath("./a/@href").extract_first()
26             url = "http://politics.people.com.cn" + url
27             pub_time = new.xpath("./em/text()").extract_first()
28 
29             item["title"] = title
30             item["url"] = url
31             item["pub_time"] = pub_time
32             yield scrapy.Request(url=url, meta={"item": item}, callback=self.parse_detail,
33                                  dont_filter=True)  # 必需要加上 dont_filter 參數
34 
35         # 下一頁
36         next_page_url = response.xpath("//div[@class='page_n clearfix']/a[last()]/@href").extract_first()
37         next_page_url = "http://politics.people.com.cn/GB/1024/" + next_page_url
38         is_active = response.xpath("//div[@class='page_n clearfix']/a[last()]/@href").extract_first()
39 
40         if next_page_url and is_active != "common_current_page":
41             yield scrapy.Request(url=next_page_url, callback=self.parse, dont_filter=True)  # 必需要加上 dont_filter 參數
42 
43     def parse_detail(self, response):
44         item = response.meta["item"]
45         article = ""
46         content_list = response.xpath("//div[@class='fl text_con_left']//p/text()").extract()
47         for content in content_list:
48             content = content.strip()
49             article += content
50         print(article)
51         item["content"] = article
52         yield item

spiders.py 這裏會有坑的,人民網他的url設計的時候跨度比較大 allowed_domains = ['people.com.cn'] 有時候沒法匹配的上,這個時候會控制檯會報以下錯:數據庫

2019-02-11 00:25:51 [scrapy.spidermiddlewares.offsite] DEBUG: Filtered offsite request to 'politics.people.com.cn': <GET http://politics.people.com.cn/n1/2019/0210/c1024-30616296.html>

解決的辦法就是將allowed_domains = ['people.com.cn'] 註釋掉,若是還不能解決就加上 dont_filter ,表示本次請求不要要對url進行過濾。ubuntu

 settings.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 \
              Safari/537.36 SE 2.X MetaSr 1.0'

ROBOTSTXT_OBEY = False

ITEM_PIPELINES = {
    # 'people.pipelines.PeoplePipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 400,
}

# 使用scrapy-redis的去重規則
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis的引擎
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 暫停功能
SCHEDULER_PERSIST = True
# 默認的scrapy-redis請求隊列形式(按優先級)
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
# 註釋掉默認使用主機的redis
# REDIS_HOST = '192.168.48.128'
# REDIS_PORT = 6379
 piplines.py

將redis裏面的數據存儲至mongodb / mysql 這裏我在網上找到了一些文章我本身尚未取驗證,目前主流的作法是單獨的寫腳本,從redis裏面取數據,我是以爲這種作法特別的很差、特別的low,等我驗證了網上的一些教程後在來貼出來。網絡

結束語:

ok,scrapy真的是一個可拓展性很強的框架,短短的幾行設置就可以實現分佈式,往後我會更新一些反爬蟲措施強一點的網站、模擬登陸、以及scrapy的源碼解讀。總是爬一些無反爬措施的網站真的沒什麼意思。休息了休息了~框架

相關文章
相關標籤/搜索