爬蟲——綜合案例流程版

爬蟲綜合案例

開發步驟:

  • 導入類庫
  • 建立爬蟲通用類
  • 初始化init方法
  • 類中編寫重試下載模塊
  • 類中編寫真正下載模塊
  • 類外編寫保存函數
  • 類外編寫獲取robots.txt函數
  • 類外編寫抽取網址函數
  • 類中編寫網址正常化函數
  • 建立下載限流類
  • 爬蟲通用類封裝run方法
  • 建立爬蟲對象運行

導入類庫

  • requests:爬蟲請求類庫
  • hashlib:哈希加密類庫
  • queue:隊列
  • re:正則
  • time:時間
  • threading>Thread:多線程
  • datetime>datetime:日期時間
  • urllib>parse>urlparse,urljoin,urldefrag:網址解析、拼接、截#取
  • urllib>robotparser:robot.txt解析
  • 目錄名>文件名>MongoCache:存儲到mongodb

建立爬蟲通用類

功能:從初始網址爬取並抽取內層網址繼續爬取
技術:隨機User-Agent生成,隊列,多線程,robots解析,下載限流,mongodb存儲,爬取深度限制,重試下載,抽取特定路由,真正下載,網址正常化,功能封裝
規範:用到類屬性和類方法的方法在類裏編寫,用不到的在類外面編寫,能夠建個助手目錄utils存放這些助手函數html

初始化init方法

一般在開發過程當中不可能一會兒就把init寫得完整,先把最易用到的,已經想到的初始化,後面的在編寫其餘函數想到時再來init裏編寫mongodb

  • 生成UserAgent對象,隨機生成headers
  • 保存初始網址
  • 建立隊列並放入初始網址

使用不一樣的隊列會形成BFS和DFS的效果 使用先進先出隊列產生廣度優先搜索,使用先進後出(棧)產生深度優先搜索多線程

  • 建立robots解析對象傳入初始網址
  • 設置指定路由
  • 建立限流器對象並初始化間隔時間
  • 建立mongodb存儲對象
  • 設置網址訪問深度,在類外設置最大深度定量

類中編寫重試下載模塊

  • 調用retry裝飾器裝飾該函數並設置最多重試次數
  • 設置函數參數:網址,數據,請求方式,代理
  • 編寫POST和GET爬取方式
  • 插入斷言:狀態碼不爲200則拋出異常
  • 返回爬取結果content


text:返回的是unicode 型的數據,通常是在網頁的header中定義的編碼形式,若是想要提取文本就用text;
content:返回的是bytes,二級制型的數據;想要提取圖片、文件,就要用到content;
.text是現成的字符串,.content還要編碼,可是.text不是全部時候顯示都正常,這是就須要用.content進行手動編碼。dom

類中編寫真正下載模塊

將重試下載模塊封裝在此,不對用戶展現重試下載接口函數

 

  • 函數參數:網址,數據(默認None),請求方式(默認GET),代理(默認爲空)
  • 輸出一句下載信息
  • try~except 捕獲重試下載模塊的異常
  • 返回結果


類外編寫保存函數

保存函數:將爬取內容MD5加密存儲到文件中,注:使用mongodb保存結果則無需次函數工具

 

  • 建立md5加密對象
  • 加密update結果
  • 拼接保存文件路徑
  • 寫入文件

類外編寫獲取robots.txt函數

  • 建立robot文件解析對象
  • 拼接robots.txt所在完整地址
  • 獲取robots.txt文件
  • 將robot.txt文件讀取到rp對象中
  • 返回該解析對象

類外編寫抽取網址函數

方式:lxml、BeautifulSoup、正則網站

lxml編碼

1 html = lxml.html.fromstring(html_content) 2 html_data = html.xpath('//a/@href')

BeautifulSoup加密

1 soup = BeautifulSoup('lxml') 2 a_list = soup.find_all('a') 3 for a in a_list: 4 print(a['href'])

正則url

1 url_regex = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE) 2 return url_regex.findall(html_content.decode("utf-8"))


decode解碼問題:不一樣網站所使用的編碼方式有所不一樣—— utf-8 , gbk, gb2312, ISO-8859-1


類中編寫網址正常化函數

實現一個類方法的時候,要注意類方法是否使用了當前類的屬性或其餘方法,若是未使用就說明和當前類沒有直接關係,最好獨立出來,當作工具方法

 

  • 以網址中的#進行分割(urldefrag),提取出網址部分和#後的轉發部分
  • 將下載地址拼接上網址部分(urljoin)
 1 urljoin:拼接網址,若參數2網址是正確格式,那麼拼接的結果只是參數2網址,參數1網址忽略;若參數2網址是錯誤格式或是後綴path,那麼和參數1網址進行拼接  2 urljoin('http://www.baidu.com','/ljb.html/index.html')  3 'http://www.baidu.com/ljb.html/index.html'
 4 
 5 urljoin('http://www.baidu.com','http://ljb.html/index.html')  6 'http://ljb.html/index.html'
 7 
 8 urljoin('/www.baidu.com','http://ljb.html/index.html')  9 'http://ljb.html/index.html'
10 
11 urljoin('/test.html','http://ljb.html/index.html') 12 'http://ljb.html/index.html'
13 
14 urljoin('http://www.baidu.com/test.html','http://ljb.html/index.html') 15 'http://ljb.html/index.html'
16 
17 urljoin('http://www.baidu.com/test.html','http://www.sina.com/ljb.html/index.html') 18 'http://www.sina.com/ljb.html/index.html'

建立下載限流類

限流:設置爬取的間隔時間是爲了不IP被封鎖,隨機間隔時間更可靠


初始化方法

  • 建立domains字典,網址爲鍵,訪問時間爲值
  • 傳參delay,自行設置兩次下載間隔時間

間隔方法

  • 原理:以delay做爲時間間隔或超過delay纔可進行訪問(爬取)
  • 第一次訪問:獲取不到網址對應的訪問時間(不執行if-else語句),以網址地址爲鍵,訪問時間爲值存入字典
  • 第二次訪問:獲取上次訪問對應網址的訪問時間,進行if-else判斷,計算時間差
  • 注:若delay>(此次訪問時間-上次訪問時間),說明還沒等夠,還須要繼續等待,還需等待的時間是——總等待時間delay減去已經等待的時間(就是當前時間減去本次訪問的時間)
  • 注:若delay<(此次訪問時間-上次訪問時間),說明已經等夠了,能夠直接訪問
  • 獲得鍵(域名):urlparse().netloc
    1 urlparse('http://www.baidu.com/index.html?x=123&y=789#13579') 2 ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='', query='x=123&y=789', fragment='13579')
  • 從domains字典中get獲取上次訪問時間
  • 經過ifelse計算還需等待的時間並睡眠(time.sleep) -一次訪問後保存本次訪問到domains字典中

爬蟲通用類封裝run方法

執行流程

  • 判斷隊列中是否存在待爬取的網址
  • 判斷爬取網址是否遵照robots約定,不遵照則跳出禁止下載
  • 對當前爬取網址限流
  • 獲取當前的訪問深度
  • 判斷當前訪問深度是否在規定範圍內
  • 下載爬取網址獲得爬取結果
  • 判斷爬取結果是否爲空
  • 爬取結果不爲空則保存
  • 獲取出爬取結果裏的全部連接
  • 使用過濾器篩選出指點關鍵字的連接
  • for循環補全每一個連接
  • 補全同時判斷連接是否訪問過
  • 未被訪問過則深度加1
  • 並加入隊列
相關文章
相關標籤/搜索