參考博客:點擊這裏html
1、scrapy安裝配置python
Linux pip3 install scrapy Windows a. pip3 install wheel b. 下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted c. 進入下載目錄,執行 pip3 install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl d. pip3 install scrapy e. 下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/
2、建立並運行scrapyredis
1. scrapy startproject 項目名稱 - 在當前目錄中建立中建立一個項目文件(相似於Django) 2. scrapy genspider [-t template] <name> <domain> - 建立爬蟲應用 如: scrapy gensipider -t basic oldboy oldboy.com scrapy gensipider -t xmlfeed autohome autohome.com.cn PS: 查看全部命令:scrapy gensipider -l 查看模板命令:scrapy gensipider -d 模板名稱 3. scrapy list - 展現爬蟲應用列表 4. scrapy crawl 爬蟲應用名稱 - 運行單獨爬蟲應用
注意:
6.運行流程數據庫
Scrapy是一個爲了爬取網站數據,提取結構性數據而編寫的應用框架。 其能夠應用在數據挖掘,信息處理或存儲歷史數據等一系列的程序中。
其最初是爲了頁面抓取 (更確切來講, 網絡抓取 )所設計的, 也能夠應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。Scrapy用途普遍,能夠用於數據挖掘、監測和自動化測試。cookie
Scrapy 使用了 Twisted異步網絡庫來處理網絡通信。總體架構大體以下網絡
Scrapy主要包括瞭如下組件:架構
Scrapy運行流程大概以下:app
3、實例:框架
1.dom
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from scrapy.http import Request 4 from scrapy.selector import Selector 5 from scrapy.http.cookies import CookieJar 6 7 class ChoutiSpider(scrapy.Spider): 8 #爬蟲名稱,必須 9 name = 'chouti' 10 #容許的url範圍 11 allowed_domains = ['chouti.com'] 12 #起始url 13 start_urls = ['http://dig.chouti.com/'] 14 #維護請求cookies 15 cookie_dict = {} 16 17 def start_requests(self): 18 """ 19 根據繼承的類源碼,自定製本身的起始函數,如沒有此函數則用 20 繼承類默認的函數,本質就是生成一個生成器,next生成器作操做 21 :return:Request() 22 """ 23 for url in self.start_urls: 24 yield Request(url,dont_filter=True,callback=self.login) 25 26 def login(self, response): 27 """ 28 獲取響應頁面發來的cookies,分析登陸請求,獲取所需數據進行登陸 29 :param response: 首頁內容 30 :return: 31 """ 32 33 #獲取cookie 34 cookie_jar = CookieJar() 35 cookie_jar.extract_cookies(response,response.request) 36 for k,v in cookie_jar._cookies.items(): 37 for i,j in v.items(): 38 for m,n in j.items(): 39 self.cookie_dict[m] = n.value 40 41 #登陸須要的post數據 42 post_data = { 43 'phone':'861767712xxxx', 44 'password':'xxxx', 45 'oneMonth':1, 46 } 47 import urllib.parse 48 49 yield Request( 50 url="http://dig.chouti.com/login", 51 method='POST', 52 cookies=self.cookie_dict, 53 #將字典轉化成k1=v1&k2=v2的格式,放在請求頭中 54 body=urllib.parse.urlencode(post_data), 55 headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, 56 callback=self.show 57 ) 58 59 def show(self,response): 60 """ 61 登陸成功,獲取新聞列表 62 :return: 63 """ 64 yield Request(url='http://dig.chouti.com/',cookies=self.cookie_dict,callback=self.find_tag) 65 66 def find_tag(self,response): 67 """ 68 分析每個頁面取到點贊id,發送POST請求對每個頁面的文章進行點贊 69 :return: 70 """ 71 hxs = Selector(response=response) 72 link_id_list = hxs.xpath('//div[@class="part2"]/@share-linkid').extract() 73 print(link_id_list) 74 for link_id in link_id_list: 75 #獲取首頁全部文章ID點贊 76 link_url = 'http://dig.chouti.com/link/vote?linksId=%s' % link_id 77 yield Request(url=link_url,method="POST",cookies=self.cookie_dict,callback=self.show_res) 78 79 #獲取其它分頁的文章點贊 80 page_list = hxs.xpath('//div[@id="dig_lcpage"]//a/@href').extract() 81 print(1) 82 for page in page_list: 83 page_url = "http://dig.chouti.com%s" % (page,) 84 #將每一頁結果從新交給這個函數,遞歸的執行每一頁的點贊 85 yield Request(url=page_url,method='GET',callback=self.find_tag) 86 87 def show_res(self,response): 88 """ 89 顯示點贊結果 90 :param response: 91 :return: 92 """ 93 print(response.text)
4、高級
1.持久化:
爬蟲數據爬取後的結果通過xpath取到須要的值,能夠交給爬蟲主目錄下的items.py的類進行規則化封裝,
yield這個item,交給pipelines進行持久化處理
爬蟲.py:
from ..items import Sp1Item
yield Sp1Item(url=url,text=text)
items.py:
class Sp1Item(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() url = scrapy.Field() text = scrapy.Field()
pipeline:
1持久化: item,pipeline pipeline執行的前提: - spider中yield Item對象 - settings中註冊 ITEM_PIPELINES = {
#權重,越小優先級越高 'sp2.pipelines.Sp2Pipeline': 300, 'sp2.pipelines.Sp2Pipeline': 100, } 編寫pipeline class Sp2Pipeline(object): def __init__(self): self.f = None def process_item(self, item, spider): """ :param item: 爬蟲中yield回來的對象 :param spider: 爬蟲對象 obj = JanDanSpider() :return: """ print(item) self.f.write('....') return item # from scrapy.exceptions import DropItem # raise DropItem() 下一個pipeline的process_item方法不在執行 @classmethod def from_crawler(cls, crawler): """ 初始化時候,用於建立pipeline對象 :param crawler: :return: """
#crawler包含爬蟲相關的全部東西,.settings可讀取配置文件 # val = crawler.settings.get('MMMM') print('執行pipeline的from_crawler,進行實例化對象') #return cls(val)
return cls() def open_spider(self,spider): """ 爬蟲開始執行時,調用 :param spider: :return: """ print('打開爬蟲') self.f = open('a.log','a+') def close_spider(self,spider): """ 爬蟲關閉時,被調用 :param spider: :return: """ self.f.close() PipeLine是全局生效,全部爬蟲都會執行,個別作特殊操做: spider.name
運行順序:
1.首先檢測 CustomPipeline類中是否有 from_crawler方法。
若是有, obj = 類.from_crawler() 此方法的本質也是實例化對象,但能夠預留一些鉤子,好比讀取配置文件,將參數寫入
若是沒有,obj = 類()
2.執行obj.open_spider()方法 (1次)
3.while True:
爬蟲運行,而且執行parse各類方法,若是在爬蟲代碼中yield了Item,則會執行obj.process_item()
4.執行完爬蟲代碼,執行obj.close_spider() (1次)
在二、4步驟時,整個代碼運行只會進行一次,所以打開爬蟲時能夠打開文件或者鏈接數據庫,close_spider時,能夠關閉文件或數據庫,而在爬蟲運行過程當中的process_item中能夠進行寫入操做,
如此能夠避免重複打開文件或數據庫,減少資源的消耗。
多個pipeline
當有多個pipeline時,默認的執行數序爲p1.__init__--p2.__init__,
p1.open_spider()--p2.o...--p1.proce...--p2.pro..--p1.close_spider--p2.clo..
這樣的好處是同一爬蟲能夠定製2個pipeline處理持久化,如一個鏈接數據庫,
另外一個寫入文件中
即,在p1.process_item()中 return item,就是將item傳入p2來進行處理,
若是p1的process方法執行完後,不想執行p2的process方法,則須要導入
DropItem模塊,再也不return item ,經過raise DropItem()便可終止p2.process方法
pipeline是全局生效,若是想對特殊爬蟲特殊操做,則經過process_item中的spider
參數,經過spider.name進行單個爬蟲的判斷。
"""
from scrapy.exceptions import DropItem
"""
2.去重規則
scrapy默認使用的去重:settings配置文件(內部,settings文件沒有)
DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'
DUPEFILTER_DEBUG = False
JOBDIR = "保存範文記錄的日誌路徑,如:/root/" # 最終路徑爲 /root/requests.seen
實例化時from_settings讀取配置文件,如配置文件沒有設置,則使用默認的
去重規則,主要函數爲request_seen(),用來查看url是否訪問過。
須要自定義時,只須要在settings配置py文件的路徑便可生效 DUPEFILTER_CLASS = 'scrapyXXX.XXX.XXX'
class RepeatUrl: def __init__(self): self.visited_url = set() # 放在當前服務的內存,此處能夠用redis等代替 @classmethod def from_settings(cls, settings): """ 初始化時,調用 :param settings: :return: """ return cls() def request_seen(self, request): """ 檢測當前請求是否已經被訪問過 :param request: :return: True表示已經訪問過;False表示未訪問過 """ if request.url in self.visited_url: return True self.visited_url.add(request.url) return False def open(self): """ 開始爬去請求時,調用 :return: """ print('open replication') def close(self, reason): """ 結束爬蟲爬取時,調用 :param reason: :return: """ print('close replication') def log(self, request, spider): """每次請求都會運行,記錄日誌 :param request: :param spider: :return: """ print('repeat', request.url)
3.基於信號的自定義規則:
如Django中同樣,scrapy也預留了不少能夠擴展的鉤子,只須要在settings裏面註冊一下並編寫類便可
EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,(文件路徑,權重)
}
from scrapy import signals class MyExtension(object): def __init__(self, value): self.value = value @classmethod def from_crawler(cls, crawler): val = crawler.settings.getint('MMMM') ext = cls(val) # 在scrapy中註冊信號: spider_opened,signal=signals.spider_opened指的是, #當spider開始運行時執行,第一個參數則是指定執行哪一個函數。 crawler.signals.connect(ext.opened, signal=signals.spider_opened) # 在scrapy中註冊信號: spider_closed,同理這裏爲spider結束時執行 crawler.signals.connect(ext.closed, signal=signals.spider_closed) return ext def opened(self, spider): print('open') def closed(self, spider): print('close')
4.中間件
1.爬蟲中間件:
class SpiderMiddleware(object): def process_spider_input(self,response, spider): """ 下載完成,執行,而後交給parse處理 :param response: :param spider: :return: """ pass def process_spider_output(self,response, result, spider): """ spider處理完成,返回時調用 :param response: :param result: :param spider: :return: 必須返回包含 Request 或 Item 對象的可迭代對象(iterable) """ return result def process_spider_exception(self,response, exception, spider): """ 異常調用 :param response: :param exception: :param spider: :return: None,繼續交給後續中間件處理異常;含 Response 或 Item 的可迭代對象(iterable),交給調度器或pipeline """ return None def process_start_requests(self,start_requests, spider): """ 爬蟲啓動時調用 :param start_requests: :param spider: :return: 包含 Request 對象的可迭代對象 """ return start_requests
2.下載中間件
每次下載以前會執行,能夠用來設置代理等工做,下載以後執行,可用來對下載的Response內容進一步封裝
class DownMiddleware1(object): def process_request(self, request, spider): """ 請求須要被下載時,通過全部下載器中間件的process_request調用 :param request: :param spider: :return: None,繼續後續中間件去下載; Response對象,中止process_request的執行,開始執行process_response Request對象,中止中間件的執行,將Request從新調度器 raise IgnoreRequest異常,中止process_request的執行,開始執行process_exception """ pass def process_response(self, request, response, spider): """ spider處理完成,返回時調用 :param response: :param result: :param spider: :return: Response 對象:轉交給其餘中間件process_response Request 對象:中止中間件,request會被從新調度下載 raise IgnoreRequest 異常:調用Request.errback """ print('response1') return response def process_exception(self, request, exception, spider): """ 當下載處理器(download handler)或 process_request() (下載中間件)拋出異常 :param response: :param exception: :param spider: :return: None:繼續交給後續中間件處理異常; Response對象:中止後續process_exception方法 Request對象:中止中間件,request將會被從新調用下載 """ return None 下載器中間件