国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

使用Python編寫多線程爬蟲抓取百度貼吧郵箱與手機號

開發 后端
其實多線程爬蟲的編寫也不復雜,多看示例代碼,多自己動手嘗試,多去社區,論壇交流,很多經典的書上對多線程編程也有非常詳細的解釋。這篇文章本質上主要還是一篇科普文章,內容講解的都不是很深入,大家還需要課外自己多結合網上各種資料自己學習。

不知道大家過年都是怎么過的,反正欄主是在家睡了一天,醒來的時候登QQ發現有人找我要一份貼吧爬蟲的源代碼,想起之前練手的時候寫過一個抓取百度貼吧發帖記錄中的郵箱與手機號的爬蟲,于是開源分享給大家學習與參考。

需求分析:

本爬蟲主要是對百度貼吧中各種帖子的內容進行抓取,并且分析帖子內容將其中的手機號和郵箱地址抓取出來。主要流程在代碼注釋中有詳細解釋。

測試環境:

代碼在Windows7 64bit,python 2.7 64bit(安裝mysqldb擴展)以及centos 6.5,python 2.7(帶mysqldb擴展)環境下測試通過

環境準備:

工欲善其事必先利其器,大家可以從截圖看出我的環境是Windows 7 + PyCharm。我的Python環境是Python 2.7 64bit。這是比較適合新手使用的開發環境。然后我再建議大家安裝一個easy_install,聽名字就知道這是一個安裝器,它是用來安裝一些擴展包的,比如說在python中如果我們要操作mysql數據庫的話,python原生是不支持的,我們必須安裝mysqldb包來讓python可以操作mysql數據庫,如果有easy_install的話我們只需要一行命令就可以快速安裝號mysqldb擴展包,他就像php中的composer,centos中的yum,Ubuntu中的apt-get一樣方便。

相關工具可在我的github中找到:cw1997/python-tools,其中easy_install的安裝只需要在python命令行下運行那個py腳本然后稍等片刻即可,他會自動加入Windows的環境變量,在Windows命令行下如果輸入easy_install有回顯說明安裝成功。

環境選擇的細節說明:

至于電腦硬件當然是越快越好,內存起碼8G起步,因為爬蟲本身需要大量存儲和解析中間數據,尤其是多線程爬蟲,在碰到抓取帶有分頁的列表和詳情頁,并且抓取數據量很大的情況下使用queue隊列分配抓取任務會非常占內存。包括有的時候我們抓取的數據是使用json,如果使用mongodb等nosql數據庫存儲,也會很占內存。

網絡連接建議使用有線網,因為市面上一些劣質的無線路由器和普通的民用無線網卡在線程開的比較大的情況下會出現間歇性斷網或者數據丟失,掉包等情況,這個我親有體會。

至于操作系統和python當然肯定是選擇64位。如果你使用的是32位的操作系統,那么無法使用大內存。如果你使用的是32位的python,可能在小規模抓取數據的時候感覺不出有什么問題,但是當數據量變大的時候,比如說某個列表,隊列,字典里面存儲了大量數據,導致python的內存占用超過2g的時候會報內存溢出錯誤。原因在我曾經segmentfault上提過的問題中依云的回答有解釋(java – python只要占用內存達到1.9G之后httplib模塊就開始報內存溢出錯誤 – SegmentFault

如果你準備使用mysql存儲數據,建議使用mysql5.5以后的版本,因為mysql5.5版本支持json數據類型,這樣的話可以拋棄mongodb了。(有人說mysql會比mongodb穩定一點,這個我不確定。)

至于現在python都已經出了3.x版本了,為什么我這里還使用的是python2.7?我個人選擇2.7版本的原因是自己當初很早以前買的python核心編程這本書是第二版的,仍然以2.7為示例版本。并且目前網上仍然有大量的教程資料是以2.7為版本講解,2.7在某些方面與3.x還是有很大差別,如果我們沒有學過2.7,可能對于一些細微的語法差別不是很懂會導致我們理解上出現偏差,或者看不懂demo代碼。而且現在還是有部分依賴包只兼容2.7版本。我的建議是如果你是準備急著學python然后去公司工作,并且公司沒有老代碼需要維護,那么可以考慮直接上手3.x,如果你有比較充裕的時間,并且沒有很系統的大牛帶,只能依靠網上零零散散的博客文章來學習,那么還是先學2.7在學3.x,畢竟學會了2.7之后3.x上手也很快。

多線程爬蟲涉及到的知識點:

其實對于任何軟件項目而言,我們凡是想知道編寫這個項目需要什么知識點,我們都可以觀察一下這個項目的主要入口文件都導入了哪些包。

現在來看一下我們這個項目,作為一個剛接觸python的人,可能有一些包幾乎都沒有用過,那么我們在本小節就來簡單的說說這些包起什么作用,要掌握他們分別會涉及到什么知識點,這些知識點的關鍵詞是什么。這篇文章并不會花費長篇大論來從基礎講起,因此我們要學會善用百度,搜索這些知識點的關鍵詞來自學。下面就來一一分析一下這些知識點。

HTTP協議:

我們的爬蟲抓取數據本質上就是不停的發起http請求,獲取http響應,將其存入我們的電腦中。了解http協議有助于我們在抓取數據的時候對一些能夠加速抓取速度的參數能夠精準的控制,比如說keep-alive等。

threading模塊(多線程):

我們平時編寫的程序都是單線程程序,我們寫的代碼都在主線程里面運行,這個主線程又運行在python進程中。關于線程和進程的解釋可以參考阮一峰的博客:進程與線程的一個簡單解釋 – 阮一峰的網絡日志

在python中實現多線程是通過一個名字叫做threading的模塊來實現。之前還有thread模塊,但是threading對于線程的控制更強,因此我們后來都改用threading來實現多線程編程了。

關于threading多線程的一些用法,我覺得這篇文章不錯:[python] 專題八.多線程編程之thread和threading 大家可以參考參考。

簡單來說,使用threading模塊編寫多線程程序,就是先自己定義一個類,然后這個類要繼承threading.Thread,并且把每個線程要做的工作代碼寫到一個類的run方法中,當然如果線程本身在創建的時候如果要做一些初始化工作,那么就要在他的__init__方法中編寫好初始化工作所要執行的代碼,這個方法就像php,java中的構造方法一樣。

這里還要額外講的一點就是線程安全這個概念。通常情況下我們單線程情況下每個時刻只有一個線程在對資源(文件,變量)操作,所以不可能會出現沖突。但是當多線程的情況下,可能會出現同一個時刻兩個線程在操作同一個資源,導致資源損壞,所以我們需要一種機制來解決這種沖突帶來的破壞,通常有加鎖等操作,比如說mysql數據庫的innodb表引擎有行級鎖等,文件操作有讀取鎖等等,這些都是他們的程序底層幫我們完成了。所以我們通常只要知道那些操作,或者那些程序對于線程安全問題做了處理,然后就可以在多線程編程中去使用它們了。而這種考慮到線程安全問題的程序一般就叫做“線程安全版本”,比如說php就有TS版本,這個TS就是Thread Safety線程安全的意思。下面我們要講到的Queue模塊就是一種線程安全的隊列數據結構,所以我們可以放心的在多線程編程中使用它。

***我們就要來講講至關重要的線程阻塞這個概念了。當我們詳細學習完threading模塊之后,大概就知道如何創建和啟動線程了。但是如果我們把線程創建好了,然后調用了start方法,那么我們會發現好像整個程序立馬就結束了,這是怎么回事呢?其實這是因為我們在主線程中只有負責啟動子線程的代碼,也就意味著主線程只有啟動子線程的功能,至于子線程執行的那些代碼,他們本質上只是寫在類里面的一個方法,并沒在主線程里面真正去執行他,所以主線程啟動完子線程之后他的本職工作就已經全部完成了,已經光榮退場了。既然主線程都退場了,那么python進程就跟著結束了,那么其他線程也就沒有內存空間繼續執行了。所以我們應該是要讓主線程大哥等到所有的子線程小弟全部執行完畢再光榮退場,那么在線程對象中有什么方法能夠把主線程卡住呢?thread.sleep嘛?這確實是個辦法,但是究竟應該讓主線程sleep多久呢?我們并不能準確知道執行完一個任務要多久時間,肯定不能用這個辦法。所以我們這個時候應該上網查詢一下有什么辦法能夠讓子線程“卡住”主線程呢?“卡住”這個詞好像太粗鄙了,其實說專業一點,應該叫做“阻塞”,所以我們可以查詢“python 子線程阻塞主線程”,如果我們會正確使用搜索引擎的話,應該會查到一個方法叫做join(),沒錯,這個join()方法就是子線程用于阻塞主線程的方法,當子線程還未執行完畢的時候,主線程運行到含有join()方法的這一行就會卡在那里,直到所有線程都執行完畢才會執行join()方法后面的代碼。

Queue模塊(隊列):

假設有一個這樣的場景,我們需要抓取一個人的博客,我們知道這個人的博客有兩個頁面,一個list.php頁面顯示的是此博客的所有文章鏈接,還有一個view.php頁面顯示的是一篇文章的具體內容。

如果我們要把這個人的博客里面所有文章內容抓取下來,編寫單線程爬蟲的思路是:先用正則表達式把這個list.php頁面的所有鏈接a標簽的href屬性抓取下來,存入一個名字叫做article_list的數組(在python中不叫數組,叫做list,中文名列表),然后再用一個for循環遍歷這個article_list數組,用各種抓取網頁內容的函數把內容抓取下來然后存入數據庫。

如果我們要編寫一個多線程爬蟲來完成這個任務的話,就假設我們的程序用10個線程把,那么我們就要想辦法把之前抓取的article_list平均分成10份,分別把每一份分配給其中一個子線程。

但是問題來了,如果我們的article_list數組長度不是10的倍數,也就是文章數量并不是10的整數倍,那么***一個線程就會比別的線程少分配到一些任務,那么它將會更快的結束。

如果僅僅是抓取這種只有幾千字的博客文章這看似沒什么問題,但是如果我們一個任務(不一定是抓取網頁的任務,有可能是數學計算,或者圖形渲染等等耗時任務)的運行時間很長,那么這將造成極大地資源和時間浪費。我們多線程的目的就是盡可能的利用一切計算資源并且計算時間,所以我們要想辦法讓任務能夠更加科學合理的分配。

并且我還要考慮一種情況,就是文章數量很大的情況下,我們要既能快速抓取到文章內容,又能盡快的看到我們已經抓取到的內容,這種需求在很多CMS采集站上經常會體現出來。

比如說我們現在要抓取的目標博客,有幾千萬篇文章,通常這種情況下博客都會做分頁處理,那么我們如果按照上面的傳統思路先抓取完list.php的所有頁面起碼就要幾個小時甚至幾天,老板如果希望你能夠盡快顯示出抓取內容,并且盡快將已經抓取到的內容展現到我們的CMS采集站上,那么我們就要實現一邊抓取list.php并且把已經抓取到的數據丟入一個article_list數組,一邊用另一個線程從article_list數組中提取已經抓取到的文章URL地址,然后這個線程再去對應的URL地址中用正則表達式取到博客文章內容。如何實現這個功能呢?

我們就需要同時開啟兩類線程,一類線程專門負責抓取list.php中的url然后丟入article_list數組,另外一類線程專門負責從article_list中提取出url然后從對應的view.php頁面中抓取出對應的博客內容。

但是我們是否還記得前面提到過線程安全這個概念?前一類線程一邊往article_list數組中寫入數據,另外那一類的線程從article_list中讀取數據并且刪除已經讀取完畢的數據。但是python中list并不是線程安全版本的數據結構,因此這樣操作會導致不可預料的錯誤。所以我們可以嘗試使用一個更加方便且線程安全的數據結構,這就是我們的子標題中所提到的Queue隊列數據結構。

同樣Queue也有一個join()方法,這個join()方法其實和上一個小節所講到的threading中join()方法差不多,只不過在Queue中,join()的阻塞條件是當隊列不為空空的時候才阻塞,否則繼續執行join()后面的代碼。在這個爬蟲中我便使用了這種方法來阻塞主線程而不是直接通過線程的join方式來阻塞主線程,這樣的好處是可以不用寫一個死循環來判斷當前任務隊列中是否還有未執行完的任務,讓程序運行更加高效,也讓代碼更加優雅。

還有一個細節就是在python2.7中隊列模塊的名字是Queue,而在python3.x中已經改名為queue,就是首字母大小寫的區別,大家如果是復制網上的代碼,要記得這個小區別。

getopt模塊:

如果大家學過c語言的話,對這個模塊應該會很熟悉,他就是一個負責從命令行中的命令里面提取出附帶參數的模塊。比如說我們通常在命令行中操作mysql數據庫,就是輸入mysql -h127.0.0.1 -uroot -p,其中mysql后面的“-h127.0.0.1 -uroot -p”就是可以獲取的參數部分。

我們平時在編寫爬蟲的時候,有一些參數是需要用戶自己手動輸入的,比如說mysql的主機IP,用戶名密碼等等。為了讓我們的程序更加友好通用,有一些配置項是不需要硬編碼在代碼里面,而是在執行他的時候我們動態傳入,結合getopt模塊我們就可以實現這個功能。

hashlib(哈希):

哈希本質上就是一類數學算法的集合,這種數學算法有個特性就是你給定一個參數,他能夠輸出另外一個結果,雖然這個結果很短,但是他可以近似認為是***的。比如說我們平時聽過的md5,sha-1等等,他們都屬于哈希算法。他們可以把一些文件,文字經過一系列的數學運算之后變成短短不到一百位的一段數字英文混合的字符串。

python中的hashlib模塊就為我們封裝好了這些數學運算函數,我們只需要簡單的調用它就可以完成哈希運算。

為什么在我這個爬蟲中用到了這個包呢?因為在一些接口請求中,服務器需要帶上一些校驗碼,保證接口請求的數據沒有被篡改或者丟失,這些校驗碼一般都是hash算法,所以我們需要用到這個模塊來完成這種運算。

json:

很多時候我們抓取到的數據不是html,而是一些json數據,json本質上只是一段含有鍵值對的字符串,如果我們需要提取出其中特定的字符串,那么我們需要json這個模塊來將這個json字符串轉換為dict類型方便我們操作。

re(正則表達式):

有的時候我們抓取到了一些網頁內容,但是我們需要將網頁中的一些特定格式的內容提取出來,比如說電子郵箱的格式一般都是前面幾位英文數字字母加一個@符號加http://xxx.xxx的域名,而要像計算機語言描述這種格式,我們可以使用一種叫做正則表達式的表達式來表達出這種格式,并且讓計算機自動從一大段字符串中將符合這種特定格式的文字匹配出來。

sys:

這個模塊主要用于處理一些系統方面的事情,在這個爬蟲中我用他來解決輸出編碼問題。

time:

稍微學過一點英語的人都能夠猜出來這個模塊用于處理時間,在這個爬蟲中我用它來獲取當前時間戳,然后通過在主線程末尾用當前時間戳減去程序開始運行時的時間戳,得到程序的運行時間。

如圖所示,開50個線程抓取100頁(每頁30個帖子,相當于抓取了3000個帖子)貼吧帖子內容并且從中提取出手機郵箱這個步驟共耗時330秒。

urllib和urllib2:

這兩個模塊都是用于處理一些http請求,以及url格式化方面的事情。我的爬蟲http請求部分的核心代碼就是使用這個模塊完成的。

MySQLdb:

這是一個第三方模塊,用于在python中操作mysql數據庫。

這里我們要注意一個細節問題:mysqldb模塊并不是線程安全版本,意味著我們不能在多線程中共享同一個mysql連接句柄。所以大家可以在我的代碼中看到,我在每個線程的構造函數中都傳入了一個新的mysql連接句柄。因此每個子線程只會用自己獨立的mysql連接句柄。

cmd_color_printers:

這也是一個第三方模塊,網上能夠找到相關代碼,這個模塊主要用于向命令行中輸出彩色字符串。比如說我們通常爬蟲出現錯誤,要輸出紅色的字體會比較顯眼,就要使用到這個模塊。

自動化爬蟲的錯誤處理:

如果大家在網絡質量不是很好的環境下使用該爬蟲,會發現有的時候會報如圖所示的異常,這是我為了偷懶并沒有寫各種異常處理的邏輯。

通常情況下我們如果要編寫高度自動化的爬蟲,那么就需要預料到我們的爬蟲可能會遇到的所有異常情況,針對這些異常情況做處理。

比如說如圖所示的錯誤,我們就應該把當時正在處理的任務重新塞入任務隊列,否則我們就會出現遺漏信息的情況。這也是爬蟲編寫的一個復雜點。

總結:

其實多線程爬蟲的編寫也不復雜,多看示例代碼,多自己動手嘗試,多去社區,論壇交流,很多經典的書上對多線程編程也有非常詳細的解釋。這篇文章本質上主要還是一篇科普文章,內容講解的都不是很深入,大家還需要課外自己多結合網上各種資料自己學習。

責任編輯:張燕妮 來源: @昌維
相關推薦

2011-12-05 09:56:59

2017-12-20 09:35:25

Python爬蟲百度云資源

2017-09-12 17:05:02

AndroidLoading客戶端

2009-04-02 09:26:00

百度貼吧俞軍

2020-05-28 13:10:06

僵尸網絡黑客網絡攻擊

2009-06-29 15:28:17

百度俞軍

2009-03-27 09:51:21

百度貼吧改版

2010-08-05 14:12:01

百度日本

2012-05-28 22:51:53

百度

2014-09-04 02:25:24

百度世界大會2014直達號BaiduEye

2009-04-07 09:23:28

李彥宏百度貼吧

2009-08-11 09:20:47

百度舒迅

2021-09-03 09:26:15

Python爬蟲百度百科

2018-09-06 18:37:45

百度云

2014-07-25 17:12:39

數據庫WOT2014MongoDB

2013-08-22 17:08:50

2012-03-23 12:12:37

百度開發者大會

2013-11-03 23:06:41

SiteApp
點贊
收藏

51CTO技術棧公眾號

97caopron在线视频| 日本不卡高清视频一区| 尤物tv在线精品| 国产精品福利在线| 99精品电影| 国产日韩欧美综合精品| 国产精品毛片| 宅男在线精品国产免费观看| 国产成人亚洲综合a∨婷婷| 欧美日韩成人免费视频| 久久久久久99久久久精品网站| 日本999视频| 一区二区不卡在线视频 午夜欧美不卡在 | 蜜桃国内精品久久久久软件9| 国产精品九九九| 在线观看的日韩av| 亚洲人体一区| 久久久精品一品道一区| 在线观看视频色潮| 日韩一级视频免费观看在线| 日本一区二区电影| 77777少妇光屁股久久一区| 91麻豆国产自产在线观看亚洲| 好看的日韩精品| aa级大片欧美| 在线看你懂得| 欧美mv日韩mv国产网站| 亚洲人成777| 亚洲伊人第一页| 久久99久久久欧美国产| 99热免费观看| 3d成人动漫网站| 亚洲综合资源| 亚洲综合中文字幕在线观看| 紧缚捆绑精品一区二区| 污网站免费看| 精品国产91乱码一区二区三区| 国产一区二区三区精品在线观看| 91网站免费看| 成人一区二区视频| 激情福利在线| 欧美超级免费视 在线| 亚洲国产激情| 小泽玛利亚视频在线观看| 欧美剧在线免费观看网站| 99精品国产高清一区二区麻豆| 国产欧美综合精品一区二区| 91丨porny丨户外露出| av资源网站在线观看| 欧美乱大交xxxxx| 玖玖精品视频| 黄色污网站在线免费观看| 日韩久久午夜影院| 97精品中文字幕| 日本成人在线免费视频| 日韩三级视频在线看| 天美av一区二区三区久久| av电影一区二区三区| 色噜噜狠狠色综合欧洲selulu| 国产亚洲观看| 男人的天堂成人| 精品视频免费在线| 精品久久不卡| 蜜臀av免费观看| 亚洲偷熟乱区亚洲香蕉av| 黄色欧美日韩| 久草在.com| 欧美激情国产精品| 韩国三级电影一区二区| av二区在线| 91精品国产综合久久香蕉最新版 | 国产精品理论片| 成人看片在线观看| 欧美午夜视频在线| 色婷婷国产精品| 狠狠色狠狠色综合婷婷tag| 日本三级免费观看| 亚洲欧洲在线免费| 蜜臀久久久久久久| 黄网页免费在线观看| 国产精品久久久久一区二区| 国产精品美女久久久久av爽李琼| 亚洲第一会所| 国产精品h视频| 精品国产乱码久久久久久夜甘婷婷| 久久久久久久久99精品大| 久久综合色播| 日韩免费在线视频| 最新国产精品久久精品| 9l视频自拍蝌蚪9l视频成人 | 天天av天天翘天天综合网 | 欧美一级日本a级v片| 欧美日韩激情一区二区三区| 亚洲一本二本| 成人p站proumb入口| 99久久综合狠狠综合久久止| 亚洲成av人片在线| 国产大片一区| yiren22亚洲综合伊人22| 国产91免费视频| 欧美在线你懂的| 99热精品在线| 18网站在线观看| 一区二区免费在线视频| 日韩高清有码在线| 丁香一区二区三区| 粉嫩av国产一区二区三区| 手机在线成人免费视频| 日本电影亚洲天堂| 无码av免费一区二区三区试看| 亚洲精品网址| 最新国产在线拍揄自揄视频| 婷婷久久五月天| 在线播放国产一区二区三区| 国产成+人+日韩+欧美+亚洲| 爱情电影网av一区二区 | 日韩精品自拍偷拍| 国产精品1区二区.| 国产精品nxnn| 深夜福利视频一区| 欧美性大战久久久久| 一区二区欧美日韩视频| 中文乱码免费一区二区| 久久中文字幕av| av小次郎在线| 欧美精品卡一卡二| 91成人国产在线观看| 在线精品亚洲一区二区不卡| 美女性感视频久久| 日韩成人视屏| 在线看黄网站| 日本成人性视频| 97超级碰碰碰| 337p亚洲精品色噜噜噜| av在线不卡电影| 欧美美女视频| 九色porny丨入口在线| www.com操| 噜噜噜噜噜久久久久久91| 日韩亚洲欧美中文高清在线| 亚洲男人的天堂在线观看| 激情婷婷久久| 99久久久国产| аⅴ资源新版在线天堂| 欧美精品久久久久久久自慰| 国产三级精品网站| 亚洲理论在线a中文字幕| 亚洲天堂免费看| 日本视频一区二区三区| 青青一区二区| 不卡视频观看| 在线手机福利影院| 欧美日韩激情四射| 亚洲free性xxxx护士白浆| 在线观看日韩av| 欧美三区在线视频| 国产亚洲成年网址在线观看| 噜噜噜91成人网| 精品国产精品国产偷麻豆| 日本精品不卡| se在线电影| 美女xx视频| 熟妇熟女乱妇乱女网站| 亚洲在线www| 久久人人爽人人| 亚洲精品视频二区| 在线观看日韩毛片| 最好看的中文字幕久久| 国产精品一区一区三区| 欧美色图麻豆| 精品国产一区二区三区| 国产第一亚洲| 日韩123区| lutube成人福利在线观看| 成人免费淫片免费观看| 中文精品无码中文字幕无码专区| 成人h视频在线| 97久久伊人激情网| 精品国内产的精品视频在线观看| 在线成人免费视频| 欧美性开放视频| 亚洲精品成a人| 日本一区二区免费在线观看视频 | 国产91白丝在线播放| 91好吊色国产欧美日韩在线| 亚洲视频在线二区| 欧美三日本三级少妇三99| 国产精品久久久久久久久久久久冷| 国产精品国内视频| 欧美在线视频a| 日韩免费高清在线观看| 国内自拍欧美激情| 91精品国产高清自在线| 欧美伦理91i| 欧美激情亚洲自拍| 欧美大学生性色视频| 欧美日韩第一页| 欧美风情在线观看| 久久久久久久国产| 韩日欧美一区二区|