您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關大規模異步新聞爬蟲中如何實現一個更好的網絡請求函數,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
downloader 的實現
import requests import cchardet import traceback def downloader(url, timeout=10, headers=None, debug=False, binary=False): _headers = { 'User-Agent': ('Mozilla/5.0 (compatible; MSIE 9.0; ' 'Windows NT 6.1; Win64; x64; Trident/5.0)'), } redirected_url = url if headers: _headers = headers try: r = requests.get(url, headers=_headers, timeout=timeout) if binary: html = r.content else: encoding = cchardet.detect(r.content)['encoding'] html = r.content.decode(encoding) status = r.status_code redirected_url = r.url except: if debug: traceback.print_exc() msg = 'failed download: {}'.format(url) print(msg) if binary: html = b'' else: html = '' status = 0 return status, html, redirected_url if __name__ == '__main__': url = 'http://news.baidu.com/' s, html = downloader(url) print(s, len(html))
這個downloader()函數,內置了默認的User-Agent模擬成一個IE9瀏覽器,同時接受調用者自定義的headers和timeout。使用cchardet來處理編碼問題,返回數據包括:
狀態碼:如果出現異常,設置為0
內容: 默認返回str內容。但是URL鏈接的是圖片等二進制內容時,注意調用時要設binary=True
重定向URL: 有些URL會被重定向,最終頁面的url包含在響應對象里面
新聞URL的清洗
我們先看看這兩個新聞網址:
http://xinwen.eastday.com/a/n181106070849091.html?qid=news.baidu.com
http://news.ifeng.com/a/20181106/60146589_0.shtml?_zbs_baidu_news
上面兩個帶?的網站來自百度新聞的首頁,這個問號?的作用就是告訴目標服務器,這個網址是從百度新聞鏈接過來的,是百度帶過來的流量。但是它們的表示方式不完全一樣,一個是qid=news.baidu.com, 一個是_zbs_baidu_news。這有可能是目標服務器要求的格式不同導致的,這個在目標服務器的后臺的瀏覽統計程序中可能用得到。
然后去掉問號?及其后面的字符,發現它們和不去掉指向的是相同的新聞網頁。
從字符串對比上看,有問號和沒問號是兩個不同的網址,但是它們又指向完全相同的新聞網頁,說明問號后面的參數對響應內容沒有任何影響。
正在抓取新聞的大量實踐后,我們發現了這樣的規律:
新聞類網址都做了大量SEO,它們把新聞網址都靜態化了,基本上都是以.html, .htm, .shtml等結尾,后面再加任何請求參數都無濟于事。
但是,還是會有些新聞網站以參數id的形式動態獲取新聞網頁。
那么我們抓取新聞時,就要利用這個規律,防止重復抓取。由此,我們實現一個清洗網址的函數。
g_bin_postfix = set([ 'exe', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'jpg', 'png', 'bmp', 'jpeg', 'gif', 'zip', 'rar', 'tar', 'bz2', '7z', 'gz', 'flv', 'mp4', 'avi', 'wmv', 'mkv', 'apk', ]) g_news_postfix = [ '.html?', '.htm?', '.shtml?', '.shtm?', ] def clean_url(url): # 1. 是否為合法的http url if not url.startswith('http'): return '' # 2. 去掉靜態化url后面的參數 for np in g_news_postfix: p = url.find(np) if p > -1: p = url.find('?') url = url[:p] return url # 3. 不下載二進制類內容的鏈接 up = urlparse.urlparse(url) path = up.path if not path: path = '/' postfix = path.split('.')[-1].lower() if postfix in g_bin_postfix: return '' # 4. 去掉標識流量來源的參數 # badquery = ['spm', 'utm_source', 'utm_source', 'utm_medium', 'utm_campaign'] good_queries = [] for query in up.query.split('&'): qv = query.split('=') if qv[0].startswith('spm') or qv[0].startswith('utm_'): continue if len(qv) == 1: continue good_queries.append(query) query = '&'.join(good_queries) url = urlparse.urlunparse(( up.scheme, up.netloc, path, up.params, query, '' # crawler do not care fragment )) return url
清洗url的方法都在代碼的注釋里面了,這里面包含了兩類操作:
判斷是否合法url,非法的直接返回空字符串
去掉不必要的參數,去掉靜態化url的參數
網絡爬蟲知識點
1. URL清洗
網絡請求開始之前,先把url清洗一遍,可以避免重復下載、無效下載(二進制內容),節省服務器和網絡開銷。
2. cchardet 模塊
該模塊是chardet的升級版,功能和chardet完全一樣,用來檢測一個字符串的編碼。由于是用C和C++實現的,所以它的速度非常快,非常適合在爬蟲中用來判斷網頁的編碼。
切記,不要相信requests返回的encoding,自己判斷一下更放心。上一節,我們已經列舉了一個例子來證明requests對編碼識別的錯誤,如果忘了的話,可以再去回顧一下。
3. traceback 模塊
我們寫的爬蟲在運行過程中,會出現各種異常,而且有些異常是不可預期的,也不知道它會出現在什么地方,我們就需要用try來捕獲異常讓程序不中斷,但是我們又需要看看捕獲的異常是什么內容,由此來改善我們的爬蟲。這個時候,就需要traceback模塊。
比如在downloader()函數里面我們用try捕獲了get()的異常,但是,異常也有可能是cchardet.detect()引起的,用traceback.print_exc()來輸出異常,有助于我們發現更多問題。
關于“大規模異步新聞爬蟲中如何實現一個更好的網絡請求函數”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。