《用python寫網路爬蟲》學習心得筆記

在學習python的過程中無意發現了這本書,豆瓣介紹用Python寫網路爬蟲 (豆瓣)這書比較新,我平時所學習的python爬蟲知識基本都是在知乎跟網上一些視頻教學一點點拼湊起來,感覺就是什麼都懂一部分卻好像連貫不起來,因為編程風格都是因人而異的,在爬取庫時候像有些人用urllib有些用requests,在獲取頁面信息有些用lxml也有些用beautifulsoup,後面還有cookies、表單、模擬登陸等,大家學習爬蟲就是不連貫,範圍廣,對於我來說有時候就很容易混亂了。大家先看看這本書一些摘要,這書適合有一定python基礎的閱讀

看完上面目錄,這本書內容很連貫,而且關鍵是作者自己搭建了一個網站Example web scraping website,爬蟲、數據收集、mongodb存儲緩存數據、多線程多進程、動態網頁、模擬註冊登陸、驗證碼處理跟書本一應俱全,就是讓學習的朋友能在一個穩定環境下去了解實踐爬蟲整個機制。總之這本書連貫性強,讓我重新認識python爬蟲!

好了,我後面把自己在學習過程中遇到的坑還有一些自己想法做個筆記,我也是新手,希望大家多多指教,有問題大家交流

第1章 網路爬蟲簡介

建議大家先把urllib2這個庫學了,還有一些get,post,headers,proxy的作用,都可以在這裡Python網路爬蟲學習筆記看到,個人感覺requests庫比較簡潔,遲點我會嘗試用requests重寫這些代碼練手,順便比較一下。

builtwith模塊將URL作為參數,下載該URL並對其進行分析,然後返回該網站使用的技術。whois模塊尋找網站的所有者。urlparse模塊介紹Python2.7 urlparse學習。

最後不得不說說作者這個代碼實在太健壯太繞了,我都有點暈了,最終版本link_crawler3里考慮了很多因素,但是我覺得作者這個代碼對於網站link分布剛剛好一頁的最後就是index頁碼,pop出去後得到第二頁,以此類推到最後25頁又把24頁的25頁鏈接pop出來,此時有這個頁碼不再爬取繼續pop回到第一頁,用到遞歸真的比較難理解。

第2章 三種網頁抓取方法

本書所有例子都是用lxml css選擇器,個人比較喜歡beautifulsoup select。re那個規則太多了..

csv模塊中open(xxx.csv,w)和open(xxx.csv,wb)區別是一個會換行一個不會

__call__特殊方法python __call__ 內置函數的使用 http://www.jb51.net/article/54483.htm

作者加了個回調函數,就是先把所有頁面國家下載下來再一個個從最後一個把國家信息存入csv,代碼實在健壯,考慮周到,但是閱讀不容易啊,運行時間也很慢,也許作者想告訴我們基礎基礎知識吧

第3章 下載緩存

磁碟緩存容易出錯,而且文件名多限制,我就看mongodb資料庫緩存,書中有錯誤地方要改成字典形式db.webpage.find({url:url}) 。

代碼中又構造魔法函數__getitem__,__setitem__,__delitem__用於索引操作,如字典。分別表示獲取,設置,刪除數據。__contains__ 為成員關係,用 in 和 not in 測試時定義行為。 那你會問這個為何不是一個序列的 protocol 的一部分? 這是因為當 __contains__ 未定義,Python 就會遍歷序列,如果遇到正在尋找的 item 就會返回True。

cache[url] = result #調用MongoCache類__setitem__函數 cache[url] #調用MongoCache類__getitem__函數

第5章 動態內容

當遇到一些網頁中的數據是使用JavaScript動態載入的,要想抓取該數據,需要了解網頁是如何載入該數據的。用Firefox瀏覽器里firebug找出網頁AJAX,在例子『example.webscraping.com{}&page_size=10&search_term={}』中page代表一次性爬取頁面數量,search_term就是搜索關鍵字,可以嘗試條件為空,*,.這些正則表達式匹配,以上的目的都是為了提高每個頁面的顯示數量到最大值,可以使下載次數減半。

當遇到更加複雜的AJAX,可以使用WebKit和Selenium,個人感覺WebKit貌似比較複雜,使用Selenium可以進行模擬登陸,像模擬登陸新浪微博這樣,如果你使用Selenium只要賬號密碼驗證碼就可以模擬手工輸入登陸。

這裡使用firefox瀏覽器版本不要太新,因為Selenium可能還沒跟得上更新,記得把瀏覽器path放進環境變數。

第6章 表單交互

表單提交並不是我們只把賬號密碼提交就可以的,很多網站還需要提交另外幾個域,例子中_formkey就是關鍵,伺服器端使用這個唯一ID來避免表單多次提交。每次載入網頁時,都會產生不同的ID,然後伺服器端可以通過這個ID判斷表單是否已經提交過。類似的還有時間戳,多次交互,cookie等。我添加了把cookie保存到本地代碼,這樣就不需要每次都要執行一次表單提交模擬登陸

def login_cookies(): """working login """ # 若要保存cookie,則使用cookielib.MozillaCookieJar filename = cookie1.txt cookie = cookielib.MozillaCookieJar(filename) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) ... response = opener.open(request) #保存cookie到本地 cookie.save(ignore_discard=True, ignore_expires=True) print response.geturl()def get_cookietxt_login(): # 創建MozillaCookieJar實例對象 cookie = cookielib.MozillaCookieJar() # 從文件中讀取cookie內容到變數 cookie.load(cookie.txt, ignore_discard=True, ignore_expires=True) # 創建請求的request req = urllib2.Request("http://example.webscraping.com") # 利用urllib2的build_opener方法創建一個opener opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) # 測試cookie response = opener.open(req) # print response.read() tree = lxml.html.fromstring(response.read()) print tree.cssselect(ul#navbar li a)[0].text_content() # 若登陸成功則Welcome Test account return opener

有變通方法,1手工在瀏覽器中登陸,找出瀏覽器存儲的cookie。2用上章Selenium模擬登陸找出cookie。先介紹書本例子代碼中我不熟悉的module glob.glob和os.path.expanduser

# -*- coding: utf-8 -*-import globimport os# glob.glob返回所有匹配的文件路徑列表。它只有一個參數pathname,定義了文件路徑匹配規則,這裡可以是絕對路徑,也可以是相對路徑。下面是使用glob.glob的例子:print glob.globglob.glob(r"E:PyCharmweb Scraping with Pythonchapter06*.py")# 輸出[E:\PyCharm\web Scraping with Python\chapter06\edit.py, E:\PyCharm\web Scraping with Python\chapter06\login.py]# os.path.expanduser(path) 把path中包含的"~"和"~user"轉換成用戶目錄print os.path.expanduser(~)# 輸出C:UsersAdministrator

從firefox瀏覽器載入cookie,在獲取session過程中,我的跟書本上不一樣,我的文件名是recovery.js,相應的find_ff_sessions()函數的paths也要更改。例子中這段代碼我看不懂None,False的作用,求高人指導一下下。

c = cookielib.Cookie(0, cookie.get(name, ), cookie.get(value, ), None, False, cookie.get(host, ), cookie.get(host, ).startswith(.), cookie.get(host, ).startswith(.), cookie.get(path, ), False, False, str(int(time.time()) + 3600 * 24 * 7), False, None, None, {})

最後我使用selenium寫了模擬登陸和保存cookie到本地再讀取登陸代碼

def selenium_login(): driver = webdriver.Firefox() driver.get(http://example.webscraping.com/user/login) driver.find_element_by_id(auth_user_email).send_keys(example@webscraping.com) driver.find_element_by_id(auth_user_password).send_keys(example) driver.find_element_by_css_selector(input.btn).click() driver.implicitly_wait(30) time.sleep(3) print driver.find_elements_by_css_selector(ul#navbar li a)[0].text cookie = [item["name"] + "=" + item["value"] for item in driver.get_cookies()] cookiestr = ;.join(item for item in cookie) # cookie = driver.get_cookies() filename = cookie_selenium.txt with open(filename , w+) as f: f.write(cookiestr) driver.close()def sele_cookie_login(): with open(cookie_selenium.txt) as f: cookiestr = f.read() headers = {cookie:cookiestr} req = urllib2.Request(http://example.webscraping.com/, headers = headers) response = urllib2.urlopen(req) tree = lxml.html.fromstring(response.read()) print tree.cssselect(ul#navbar li a)[0].text_content() # 若登陸成功則Welcome Test account

說實話,處理cookie有點複雜,在這裡個人總結一下:1通過表單提交,不單單要賬號密碼驗證碼這些顯而易見的信息,還需要一大堆跟伺服器交互的input數據打包成date然後urlencode整理成Request,再通過cookielib的opener集合在一起提交到伺服器,再把cookie保存在本地2手工或者selenium方便登陸獲取cookie保存在本地。

第7章 驗證碼處理

導入pytesseract直接運行OCR是不行的,會只出現WindowsError: [Error 2],其實這裡error信息沒告訴清楚使用者問題,反正當時我搞了1小時,其實是還要安裝一個軟體tesseract-ocr-setup-3.02.02.exe,下載好後要去環境變數那裡添加你安裝的地址E:Tesseract-OCR esseract.exe,OK!

在form.py里的register函數中,我添加一些報錯信息

def register(first_name, last_name, email, password1, password2, captcha_fn): cj = cookielib.CookieJar() ... result = /user/register not in response.geturl() # 判斷登陸是否成功,若成功則跳回主頁,不成功註冊頁面 if not result: # reslut為False時候檢查登陸失敗原因 result = [] error_list = { first_name__error: first_name is empty, last_name__error: last_name is empty, email__error: This email already has an account22, password__error: Too short, password_two__error: password is not match, } tree = lxml.html.fromstring(response.read()) input_error = tree.cssselect(form .error_wrapper div) if input_error != : for i in input_error: result.append(error_list[i.get(id)]) if tree.cssselect(form #recaptcha > div): # 只有登陸失敗重回註冊頁面才出現 result.append(captcha error) return result

使用外國的9kw在線打碼服務也是挺有趣的,你可以幫人家打碼獲取積分,然後用這些積分去用到代碼中請別人在線打碼,下次有空試試國內的打碼API。


推薦閱讀:

正則表達式如何匹配網頁裡面的漢字?
使用 修飾器+類 定義Python常量
Python3中dict的派生類實例不能序列化為json?
如何在互動式環境中執行Python程序
從 Node 到 Go:一個粗略的比較

TAG:Python | 網頁爬蟲 |