爬蟲——小結
爬蟲原理與資料抓取
Requests簡單使用
新增 headers 和 查詢引數
如果想新增 headers,可以傳入headers引數來增加請求頭中的headers資訊。如果要將引數放在url中傳遞,可以利用 params 引數
import requests kw = {'wd':'長城'} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # params 接收一個字典或者字串的查詢引數,字典型別自動轉換為url編碼,不需要urlencode() response = requests.get("http://www.baidu.com/s?", params = kw, headers = headers) # 檢視響應內容,response.text 返回的是Unicode格式的資料 print (response.text) # 檢視響應內容,response.content返回的位元組流資料 print (respones.content) # 檢視完整url地址 print (response.url) # 檢視響應頭部字元編碼 print (response.encoding) # 檢視響應碼 print (response.status_code)
使用response.text 時,Requests 會基於 HTTP 響應的文字編碼自動解碼響應內容,大多數 Unicode 字符集都能被無縫地解碼。 使用response.content 時,返回的是伺服器響應資料的原始二進位制位元組流,可以用來儲存圖片等二進位制檔案。
requests預設自帶的Accept-Encoding導致或者新浪預設傳送的就是壓縮之後的網頁 但是為什麼content.read()沒有問題,因為requests,自帶解壓壓縮網頁的功能 當收到一個響應時,Requests 會猜測響應的編碼方式,用於在你呼叫response.text 方法時對響應進行解碼。Requests 首先在 HTTP 頭部檢測是否存在指定的編碼方式,如果不存在,則會使用 chardet.detect來嘗試猜測編碼方式(存在誤差) 更推薦使用response.content.deocde()
Requests深入
# 如果是json檔案可以直接顯示 print (response.json()) # unquote將url格式的中文還原 a = requests.utils.unquote('http://www.baidu.com/f?kw=%E6%9D%E6%85%') print(a) http://www.baidu.com/f?kw=李子 通過本地環境變數 HTTP_PROXY 和 HTTPS_PROXY 來配置代理: export HTTP_PROXY="http://12.34.56.79:9527" export HTTPS_PROXY="https://12.34.56.79:9527"
私密代理驗證(特定格式) 和 Web客戶端驗證(auth 引數)
私密代理
import requests # 如果代理需要使用HTTP Basic Auth,可以使用下面這種格式: proxy = { "http": "mr_mao_hacker:[email protected]:16816" } response = requests.get("http://www.baidu.com", proxies = proxy) print (response.text)
web客戶端驗證
如果是Web客戶端驗證,需要新增 auth = (賬戶名, 密碼)
1 import requests 2 3 auth=('test', '123456') 4 5 response = requests.get('http://192.168.199.107', auth = auth) 6 7 print (response.text)
Cookies
1 import requests 2 3 response = requests.get("http://www.baidu.com/") 4 5 # 7\. 返回CookieJar物件: 6 cookiejar = response.cookies 7 8 # 8\. 將CookieJar轉為字典: 9 cookiedict = requests.utils.dict_from_cookiejar(cookiejar) 10 11 print (cookiejar) 12 13 print (cookiedict)
session
實現人人網登入
import requests # 1\. 建立session物件,可以儲存Cookie值 ssion = requests.session() # 2\. 處理 headers headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # 3\. 需要登入的使用者名稱和密碼 data = {"email":"", "password":""} # 4\. 傳送附帶使用者名稱和密碼的請求,並獲取登入後的Cookie值,儲存在ssion裡 ssion.post("http://www.renren.com/PLogin.do", data = data) # 5\. ssion包含使用者登入後的Cookie值,可以直接訪問那些登入後才可以訪問的頁面 response = ssion.get("http://www.renren.com/410043129/profile") # 6\. 列印響應內容 print (response.text)
處理HTTPS請求 SSL證書驗證
Requests也可以為HTTPS請求驗證SSL證書:
- 要想檢查某個主機的SSL證書,你可以使用 verify 引數(也可以不寫)
- 如果SSL證書驗證不通過,或者不信任伺服器的安全證書,則會報出SSLError,據說 12306 證書是自己做的
- 如果我們想跳過 12306 的證書驗證,把 verify 設定為 False 就可以正常請求了
SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
非結構化資料與結構化資料提取
XPath與lxml類庫
- bookstore//book
選擇屬於 bookstore 元素的後代的所有 book 元素,而不管它們位於 bookstore 之下的什麼位置
- /bookstore/book[last()-1]
選取屬於 bookstore 子元素的倒數第二個 book 元素
- /bookstore/book[position()<3]
選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素
- /bookstore/book[price>35.00]/title
選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00
- //book/title | //book/price
選取 book 元素的所有 title 和 price 元素
- //title | //price
選取文件中的所有 title 和 price 元素
- /bookstore/book/title | //price
選取屬於 bookstore 元素的 book 元素的所有 title 元素,以及文件中所有的 price 元素
- //li//span
獲取<li> 標籤下的所有 <span> 標籤
- //li/a//@class
獲取 <li> 標籤下的<a>標籤裡的所有 class
- //li[last()]/a/@href
獲取最後一個 <li> 的 <a> 的 href
JSON
json.loads()
從json到python的型別轉化
json.dumps()
從python原始型別向json型別的轉化
chardet是一個非常優秀的編碼識別模組,可通過pip安裝。chardet.detect()返回字典, 其中confidence是檢測精確度
json.dump()
將Python內建型別序列化為json物件後寫入文
1 import json 2 3 listStr = [{"city": "北京"}, {"name": "大劉"}] 4 json.dump(listStr, open("listStr.json","w"), ensure_ascii=False) 5 6 dictStr = {"city": "北京", "name": "大劉"} 7 json.dump(dictStr, open("dictStr.json","w"), ensure_ascii=False)
json.load()
讀取檔案中json形式的字串元素 轉化成python型別
1 import json 2 3 strList = json.load(open("listStr.json")) 4 print strList 5 6 # [{u'city': u'\u5317\u4eac'}, {u'name': u'\u5927\u5218'}] 7 8 strDict = json.load(open("dictStr.json")) 9 print strDict 10 # {u'city': u'\u5317\u4eac', u'name': u'\u5927\u5218'}
Queue
- Queue是python中的標準庫,可以直接import Queue引用;佇列是執行緒間最常用的交換資料的形式
- 對於資源,加鎖是個重要的環節。因為python原生的list,dict等,都是not thread safe的。而Queue,是執行緒安全的,因此在滿足使用條件下,建議使用佇列
- 初始化: class Queue.Queue(maxsize) FIFO 先進先出
- 包中的常用方法:
- Queue.qsize() 返回佇列的大小
- Queue.empty() 如果佇列為空,返回True,反之False
- Queue.full() 如果佇列滿了,返回True,反之False
- Queue.full 與 maxsize 大小對應
- Queue.get([block[, timeout]])獲取佇列,timeout等待時間
- 建立一個“佇列”物件
import Queue myqueue = Queue.Queue(maxsize = 10)
- 將一個值放入佇列中
myqueue.put(10)
- 將一個值從佇列中取出
myqueue.get()
BeautifulSoup4
lxml 只會區域性遍歷,而Beautiful Soup 是基於HTML DOM的,會載入整個文件,解析整個DOM樹,因此時間和記憶體開銷都會大很多,所以效能要低於lxml
1 print soup.name 2 # [document] #soup 物件本身比較特殊,它的 name 即為 [document] 3 4 print soup.head.name 5 # head #對於其他內部標籤,輸出的值便為標籤本身的名稱 6 7 print soup.p.attrs 8 # {'class': ['title'], 'name': 'dromouse'} 9 # 在這裡,我們把 p 標籤的所有屬性列印輸出了出來,得到的型別是一個字典。 10 11 print soup.p['class'] # soup.p.get('class') 12 # ['title'] #還可以利用get方法,傳入屬性的名稱,二者是等價的 13 14 soup.p['class'] = "newClass" 15 print soup.p # 可以對這些屬性和內容等等進行修改 16 # <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p> 17 18 del soup.p['class'] # 還可以對這個屬性進行刪除 19 print soup.p 20 # <p name="dromouse"><b>The Dormouse's story</b></p> 21 22 print soup.p.string 23 # The Dormouse's story 24 25 print type(soup.p.string) 26 # In [13]: <class 'bs4.element.NavigableString'> 27 28 # Comment 物件是一個特殊型別的 NavigableString 物件,其輸出的內容不包括註釋符號 29 print soup.a 30 # <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a> 31 32 print soup.a.string 33 # Elsie 34 35 print type(soup.a.string) 36 # <class 'bs4.element.Comment'> 37 # tag 的 .content 屬性可以將tag的子節點以列表的方式輸出 38 print soup.head.contents 39 #[<title>The Dormouse's story</title>] 40 print soup.head.contents[0] 41 #<title>The Dormouse's story</title> 42 43 # .children 返回的是一個 list 生成器物件,通過遍歷獲取所有子節點 44 print soup.head.children 45 #<listiterator object at 0x7f71457f5710> 46 47 for child in soup.body.children: 48 print child 49 50 # 所有子孫節點: .descendants 屬性 51 .contents 和 .children 屬性僅包含tag的直接子節點,.descendants 屬性可以對所有tag的子孫節點進行遞迴迴圈,和 children類似,我們也需要遍歷獲取其中的內容 52 for child in soup.descendants: 53 print child
動態HTML處理和機器影象識別
Selenium
1 # 呼叫鍵盤按鍵操作時需要引入的Keys包 2 from selenium.webdriver.common.keys import Keys 3 4 # 生成當前頁面快照並儲存 5 driver.save_screenshot("baidu.png") 6 7 # 列印網頁渲染後的原始碼 8 print driver.page_source 9 10 # 獲取當前頁面Cookie 11 print driver.get_cookies() 12 13 # ctrl+a 全選輸入框內容 14 driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a') 15 16 # ctrl+x 剪下輸入框內容 17 driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x') 18 19 # 模擬Enter回車鍵 20 driver.find_element_by_id("su").send_keys(Keys.RETURN) 21 22 # 獲取當前url 23 print driver.current_url 24 25 # 關閉當前頁面,如果只有一個頁面,會關閉瀏覽器 26 # driver.close() 27 28 # 關閉瀏覽器 29 driver.quit()
頁面操作
1 # 獲取id標籤值 2 element = driver.find_element_by_id("passwd-id") 3 # 獲取name標籤值 4 element = driver.find_element_by_name("user-name") 5 # 獲取標籤名值 6 element = driver.find_elements_by_tag_name("input") 7 # 也可以通過XPath來匹配 8 element = driver.find_element_by_xpath("//input[@id='passwd-id']") 9 10 find_element_by_id 11 find_elements_by_name 12 find_elements_by_xpath 13 find_elements_by_link_text 14 # 上下兩行區別: 15 # partial 是部分的意思,可以定位a標籤文本里的部分內容 16 find_elements_by_partial_link_text 17 find_elements_by_tag_name 18 find_elements_by_class_name 19 find_elements_by_css_selector
滑鼠動作鏈
1 #匯入 ActionChains 類 2 from selenium.webdriver import ActionChains 3 4 # 滑鼠移動到 ac 位置 5 ac = driver.find_element_by_xpath('element') 6 ActionChains(driver).move_to_element(ac).perform() 7 8 9 # 在 ac 位置單擊 10 ac = driver.find_element_by_xpath("elementA") 11 ActionChains(driver).move_to_element(ac).click(ac).perform() 12 13 # 在 ac 位置雙擊 14 ac = driver.find_element_by_xpath("elementB") 15 ActionChains(driver).move_to_element(ac).double_click(ac).perform() 16 17 # 在 ac 位置右擊 18 ac = driver.find_element_by_xpath("elementC") 19 ActionChains(driver).move_to_element(ac).context_click(ac).perform() 20 21 # 在 ac 位置左鍵單擊hold住 22 ac = driver.find_element_by_xpath('elementF') 23 ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform() 24 25 # 將 ac1 拖拽到 ac2 位置 26 ac1 = driver.find_element_by_xpath('elementD') 27 ac2 = driver.find_element_by_xpath('elementE') 28 ActionChains(driver).drag_and_drop(ac1, ac2).perform()
填充表單
1 # 匯入 Select 類 2 from selenium.webdriver.support.ui import Select 3 4 # 找到 name 的選項卡 5 select = Select(driver.find_element_by_name('status')) 6 7 # 8 select.select_by_index(1) 9 select.select_by_value("0") 10 select.select_by_visible_text(u"未稽核")
以上是三種選擇下拉框的方式,它可以根據索引來選擇,可以根據值來選擇,可以根據文字來選擇。注意:
- index 索引從 0 開始
- value是option標籤的一個屬性值,並不是顯示在下拉框中的值
- visible_text是在option標籤文字的值,是顯示在下拉框的值
- 全部取消選擇
alert = driver.switch_to_alert()
頁面切換
一個瀏覽器肯定會有很多視窗,所以我們肯定要有方法來實現視窗的切換。切換視窗的方法如下:
driver.switch_to.window("this is window name")
也可以使用 window_handles 方法來獲取每個視窗的操作物件。例如:
for handle in driver.window_handles: driver.switch_to_window(handle)
頁面前進和後退
driver.forward() #前進
driver.back() # 後退
Cookies
1 for cookie in driver.get_cookies(): 2 print "%s -> %s" % (cookie['name'], cookie['value']) 3 4 # By name 5 driver.delete_cookie("CookieName") 6 7 # all 8 driver.delete_all_cookies()
頁面等待
隱式等待是等待特定的時間,顯式等待是指定某一條件直到這個條件成立時繼續執行。
顯式等待
顯式等待指定某個條件,然後設定最長等待時間。如果在這個時間還沒有找到元素,那麼便會丟擲異常了
1 from selenium import webdriver 2 from selenium.webdriver.common.by import By 3 # WebDriverWait 庫,負責迴圈等待 4 from selenium.webdriver.support.ui import WebDriverWait 5 # expected_conditions 類,負責條件出發 6 from selenium.webdriver.support import expected_conditions as EC 7 8 driver = webdriver.Chrome() 9 driver.get("http://www.xxxxx.com/loading") 10 try: 11 # 頁面一直迴圈,直到 id="myDynamicElement" 出現 12 element = WebDriverWait(driver, 10).until( 13 EC.presence_of_element_located((By.ID, "myDynamicElement")) 14 ) 15 finally: 16 driver.quit()
如果不寫引數,程式預設會 0.5s 呼叫一次來檢視元素是否已經生成,如果本來元素就是存在的,那麼會立即返回
下面是一些內建的等待條件,你可以直接呼叫這些條件,而不用自己寫某些等待條件了
title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable – it is Displayed and Enabled.
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present
隱式等待
不設定,預設等待時間為0,單位為秒
1 from selenium import webdriver 2 3 driver = webdriver.Chrome() 4 driver.implicitly_wait(10) # seconds 5 driver.get("http://www.xxxxx.com/loading") 6 myDynamicElement = driver.find_element_by_id("myDynamicElement")
def __del__(self):
'''呼叫內建的稀構方法,在程式退出的時候自動呼叫
類似的還可以在檔案開啟的時候呼叫close,資料庫連結的斷開
'''
self.driver.quit()
# 預設這個方法是物件使用後自動銷燬物件用的,在這裡修改為物件使用後關閉瀏覽器
Tesseract與pytesseract
1 import pytesseract 2 from PIL import Image 3 4 image = Image.open('test.jpg') 5 text = pytesseract.image_to_string(image) 6 print text 7 對圖片進行閾值過濾和降噪處理 8 from PIL import Image 9 import subprocess 10 11 def cleanFile(filePath, newFilePath): 12 image = Image.open(filePath) 13 14 # 對圖片進行閾值過濾(低於143的置為黑色,否則為白色) 15 image = image.point(lambda x: 0 if x < 143 else 255) 16 # 重新儲存圖片 17 image.save(newFilePath) 18 19 # 呼叫系統的tesseract命令對圖片進行OCR識別 20 subprocess.call(["tesseract", newFilePath, "output"]) 21 22 # 開啟檔案讀取結果 23 with open("output.txt", 'r') as f: 24 print(f.read()) 25 26 if __name__ == "__main__": 27 cleanFile("text2.png", "text2clean.png")
scrapy框架
儲存資料
scrapy儲存資訊的最簡單的方法主要有四種,-o 輸出指定格式的檔案,,命令如下:
# json格式,預設為Unicode編碼
scrapy crawl itcast -o teachers.json
# json lines格式,預設為Unicode編碼
scrapy crawl itcast -o teachers.jsonl
# csv 逗號表示式,可用Excel開啟
scrapy crawl itcast -o teachers.csv
# xml格式
scrapy crawl itcast -o teachers.xml
元素選取
- contains的用法,or的用法,last()的含義
response.xpath('//*[contains(@class,"odd") or contains(@class,"even")]/td[last()]/text()').extract()
0-1000隨意設定,數值越低,元件的優先順序越高
parse()方法的工作機制
- 因為使用的yield,而不是return。parse函式將會被當做一個生成器使用。scrapy會逐一獲取parse方法中生成的結果,並判斷該結果是一個什麼樣的型別
- 如果是request則加入爬取佇列,如果是item型別則使用pipeline處理,其他型別則返回錯誤資訊
- scrapy取到第一部分的request不會立馬就去傳送這個request,只是把這個request放到佇列裡,然後接著從生成器裡獲取
- 取盡第一部分的request,然後再獲取第二部分的item,取到item了,就會放到對應的pipeline裡處理
- parse()方法作為回撥函式(callback)賦值給了Request,指定parse()方法來處理這些請求 scrapy.Request(url, callback=self.parse)
- Request物件經過排程,執行生成 scrapy.http.response()的響應物件,並送回給parse()方法,直到排程器中沒有Request(遞迴的思路)
- 取盡之後,parse()工作結束,引擎再根據佇列和pipelines中的內容去執行相應的操作
- 程式在取得各個頁面的items前,會先處理完之前所有的request佇列裡的請求,然後再提取item
- 這一切的一切,Scrapy引擎和排程器將負責到底
CrawlSpiders
rule
CrawlSpider使用rules來決定爬蟲的爬取規則,並將匹配後的url請求提交給引擎。所以在正常情況下,CrawlSpider不需要單獨手動返回請求了
- link_extractor:是一個Link Extractor物件,用於定義需要提取的連結
- callback: 從link_extractor中每獲取到連結時,引數所指定的值作為回撥函式,該回調函式接受一個response作為其第一個引數
注意:當編寫爬蟲規則時,避免使用parse作為回撥函式。由於CrawlSpider使用parse方法來實現其邏輯,如果覆蓋了 parse方法,crawl spider將會執行失敗
- follow:是一個布林(boolean)值,指定了根據該規則從response提取的連結是否需要跟進。 如果callback為None,follow 預設設定為True ,否則預設為False
- process_links:指定該spider中哪個的函式將會被呼叫,從link_extractor中獲取到連結列表時將會呼叫該函式。該方法主要用來過濾
- process_request:指定該spider中哪個的函式將會被呼叫, 該規則提取到每個request時都會呼叫該函式。 (用來過濾request)
Request和Response
傳送POST請求
- 可以使用 yield scrapy.FormRequest(url, formdata, callback)方法傳送POST請求
- 如果希望程式執行一開始就傳送POST請求,可以重寫Spider類的start_requests(self) 方法,並且不再呼叫start_urls裡的url
1 class mySpider(scrapy.Spider): 2 # start_urls = ["http://www.example.com/"] 3 4 def start_requests(self): 5 url = 'http://www.renren.com/PLogin.do' 6 7 # FormRequest 是Scrapy傳送POST請求的方法 8 yield scrapy.FormRequest( 9 url = url, 10 formdata = {"email" : "[email protected]", "password" : "axxxxxxxe"}, 11 callback = self.parse_page 12 ) 13 def parse_page(self, response): 14 # do something
模擬登陸
- 使用FormRequest.from_response()方法模擬使用者登入
- 通常網站通過 實現對某些表單欄位(如資料或是登入介面中的認證令牌等)的預填充
- 使用Scrapy抓取網頁時,如果想要預填充或重寫像使用者名稱、使用者密碼這些表單欄位, 可以使用 FormRequest.from_response() 方法實現
1 import scrapy 2 3 class LoginSpider(scrapy.Spider): 4 name = 'example.com' 5 start_urls = ['http://www.example.com/users/login.php'] 6 7 def parse(self, response): 8 return scrapy.FormRequest.from_response( 9 response, 10 formdata={'username': 'john', 'password': 'secret'}, 11 callback=self.after_login 12 ) 13 14 def after_login(self, response): 15 # check login succeed before going on 16 if "authentication failed" in response.body: 17 self.log("Login failed", level=log.ERROR) 18 return
中介軟體
防止爬蟲被反
- 動態設定User-Agent(隨機切換User-Agent,模擬不同使用者的瀏覽器資訊)
- 禁用Cookies(也就是不啟用cookies middleware,不向Server傳送cookies,有些網站通過cookie的使用發現爬蟲行為)
- 可以通過COOKIES_ENABLED 控制 CookiesMiddleware 開啟或關閉
- 設定延遲下載(防止訪問過於頻繁,設定為 2秒 或更高)
- Google Cache 和 Baidu Cache:如果可能的話,使用谷歌/百度等搜尋引擎伺服器頁面快取獲取頁面資料
- 使用IP地址池:VPN和代理IP,現在大部分網站都是根據IP來ban的
- 使用 Crawlera(專用於爬蟲的代理元件),正確配置和設定下載中介軟體後,專案所有的request都是通過crawlera發出
DOWNLOADER_MIDDLEWARES = {
'scrapy_crawlera.CrawleraMiddleware': 600
}
CRAWLERA_ENABLED = True
CRAWLERA_USER = '註冊/購買的UserKey'
CRAWLERA_PASS = '註冊/購買的Password'
下載中介軟體
1 # middlewares.py 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 import random 7 import base64 8 9 from settings import USER_AGENTS 10 from settings import PROXIES 11 12 # 隨機的User-Agent 13 class RandomUserAgent(object): 14 def process_request(self, request, spider): 15 useragent = random.choice(USER_AGENTS) 16 17 request.headers.setdefault("User-Agent", useragent) 18 19 class RandomProxy(object): 20 def process_request(self, request, spider): 21 proxy = random.choice(PROXIES) 22 23 if proxy['user_passwd'] is None: 24 # 沒有代理賬戶驗證的代理使用方式 25 request.meta['proxy'] = "http://" + proxy['ip_port'] 26 else: 27 # 對賬戶密碼進行base64編碼轉換 28 base64_userpasswd = base64.b64encode(proxy['user_passwd']) 29 # 對應到代理伺服器的信令格式裡 30 request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd 31 request.meta['proxy'] = "http://" + proxy['ip_port']
為什麼HTTP代理要使用base64編碼: HTTP代理的原理很簡單,就是通過HTTP協議與代理伺服器建立連線,協議信令中包含要連線到的遠端主機的IP和埠號,如果有需要身份驗證的話還需要加上授權資訊,伺服器收到信令後首先進行身份驗證,通過後便與遠端主機建立連線,連線成功之後會返回給客戶端200,表示驗證通過,就這麼簡單,下面是具體的信令格式:
settings
- BOT_NAME
- 預設: 'scrapybot'
- 當您使用 startproject 命令建立專案時其也被自動賦值
- CONCURRENT_ITEMS
- 預設: 100
- Item Processor(即 Item Pipeline) 同時處理(每個response的)item的最大值
- CONCURRENT_REQUESTS
- 預設: 16
- Scrapy downloader 併發請求(concurrent requests)的最大值
- DEFAULT_REQUEST_HEADERS
- 預設: 如下
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
Scrapy HTTP Request使用的預設header。
- DEPTH_LIMIT
- 預設: 0
- 爬取網站最大允許的深度(depth)值。如果為0,則沒有限制
- DOWNLOAD_DELAY
- 預設: 0
- 下載器在下載同一個網站下一個頁面前需要等待的時間。該選項可以用來限制爬取速度, 減輕伺服器壓力。同時也支援小數
- DOWNLOAD_DELAY = 0.25 # 250 ms of delay
- 預設情況下,Scrapy在兩個請求間不等待一個固定的值, 而是使用0.5到1.5之間的一個隨機值 * DOWNLOAD_DELAY 的結果作為等待間隔
- DOWNLOAD_TIMEOUT
- 預設: 180
- 下載器超時時間(單位: 秒)
- ITEM_PIPELINES
- 預設: {}
- 儲存專案中啟用的pipeline及其順序的字典。該字典預設為空,值(value)任意,不過值(value)習慣設定在0-1000範圍內,值越小優先順序越高
ITEM_PIPELINES = {
'mySpider.pipelines.SomethingPipeline': 300,
'mySpider.pipelines.ItcastJsonPipeline': 800,
}
- LOG_ENABLED
- 預設: True
- 是否啟用logging
- LOG_ENCODING
- 預設: 'utf-8'
- logging使用的編碼
- LOG_LEVEL
- 預設: 'DEBUG'
- log的最低級別。可選的級別有: CRITICAL、 ERROR、WARNING、INFO、DEBUG
- USER_AGENT
- 預設: "Scrapy/VERSION (+http://scrapy.org)"
- 爬取的預設User-Agent,除非被覆蓋
- PROXIES: 代理設定
- COOKIES_ENABLED = False
- 禁用Cookies
scrapy-redis
Scrapy-redis提供了下面四種元件(components):(四種元件意味著這四個模組都要做相應的修改)
- Scheduler
- Duplication Filter
- Item Pipeline
- Base Spider
scrapy-redis的總體思路
- 這個工程通過重寫scheduler和spider類,實現了排程、spider啟動和redis的互動
- 實現新的dupefilter和queue類,達到了判重和排程容器和redis的互動,因為每個主機上的爬蟲程序都訪問同一個redis資料庫,所以排程和判重都統一進行統一管理,達到了分散式爬蟲的目的
- 當spider被初始化時,同時會初始化一個對應的scheduler物件,這個排程器物件通過讀取settings,配置好自己的排程容器queue和判重工具dupefilter
- 每當一個spider產出一個request的時候,scrapy核心會把這個reuqest遞交給這個spider對應的scheduler物件進行排程,scheduler物件通過訪問redis對request進行判重,如果不重複就把他新增進redis中的排程池
- 當排程條件滿足時,scheduler物件就從redis的排程池中取出一個request傳送給spider,讓他爬取
- 當spider爬取的所有暫時可用url之後,scheduler發現這個spider對應的redis的排程池空了,於是觸發訊號spider_idle,spider收到這個訊號之後,直接連線redis讀取strart url池,拿去新的一批url入口,然後再次重複上邊的工作
請使用手機"掃一掃"x