OK!終於到了分布式爬蟲了,說下,我整了幾天才把分布式爬蟲給搞定。(心里苦哇)為什么會這么久,請聽我徐徐道來。
在使用分布式爬蟲的時候通用的做法是一台電腦作為master端,另外的多台電腦作為slaver端,我采用的是主機與虛擬機來搭建的環境,說說我的主機,一台聯想的y410筆記本,只有4G的內存,用到現在已經快5年了,還很堅挺 :-)就是內存小了點,我的虛擬機用的是xubuntu(輕量級的ubuntu),虛擬機作為的master端,master端的redis用來存儲數據以及url去重,主機作為slaver端執行代碼。這里面有一步很關鍵,那就是我的主機(slaver端)要能夠訪問我的虛擬機(master端)里面的redis數據庫才行,很無奈我就是卡在了這里,我的主機無論如何都無法ping通虛擬機,也就是訪問不了xubuntu的redis數據庫,在網上找了各種解決方法,都行不通,最后沒辦法了直接卸載了vnware重裝之后,又修改了下網絡配置,才最終解決問題。實屬心酸~
所以呀,如果有小伙伴遇見類似的問題,除了google之外,可以直接考慮重裝下自己的vmware。
嗯~好,當主機與虛擬機ping通之后就可以來做分布式了,具體實現細節我就不再贅余了,百度一下出來一大堆結果。我之后會寫一篇關於scrapy-redis的源碼解讀的博客。這里只是記錄一下具體代碼實現的過程。
目標網址:人民網
http://politics.people.com.cn/GB/1024/index1.html
同樣無反爬措施,可以安心使用。
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進行過濾。
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的源碼解讀。老是爬一些無反爬措施的網站真的沒什么意思。休息了休息了~