亚洲国产精品无码久久大片,亚洲AV无码乱码麻豆精品国产,亚洲品质自拍网站,少妇伦子伦精品无码STYLES,国产精久久久久久久

使用Python編撰多線(xiàn)程爬蟲(chóng)抓取*敏*感*詞*郵箱與手機號

優(yōu)采云 發(fā)布時(shí)間: 2020-07-05 08:00

  不知道你們春節都是如何過(guò)的,反正欄主是在家睡了三天,醒來(lái)的時(shí)侯登QQ發(fā)覺(jué)有人找我要一份帖吧爬蟲(chóng)的源代碼,想起之前練手的時(shí)侯寫(xiě)過(guò)一個(gè)抓取*敏*感*詞*發(fā)貼記錄中的郵箱與手機號的爬蟲(chóng),于是開(kāi)源分享給你們學(xué)習與參考。

  本爬蟲(chóng)主要是對*敏*感*詞*中各類(lèi)貼子的內容進(jìn)行抓取,并且剖析貼子內容將其中的手機號和郵箱地址抓取下來(lái)。主要流程在代碼注釋中有詳盡解釋。

  代碼在Windows7 64bit,python 2.7 64bit(安裝mysqldb擴充)以及centos 6.5,python 2.7(帶mysqldb擴充)環(huán)境下測試通過(guò)

  

  

  工欲善其事必先利其器,大家可以從截圖看出我的環(huán)境是Windows 7 + PyCharm。我的Python環(huán)境是Python 2.7 64bit。這是比較適宜菜鳥(niǎo)使用的開(kāi)發(fā)環(huán)境。然后我再建議你們安裝一個(gè)easy_install,聽(tīng)名子就曉得這是一個(gè)安裝器,它是拿來(lái)安裝一些擴充包的,比如說(shuō)在python中假如我們要操作mysql數據庫的話(huà),python原生是不支持的,我們必須安裝mysqldb包來(lái)讓python可以操作mysql數據庫,如果有easy_install的話(huà)我們只須要一行命令就可以快速安裝號mysqldb擴充包,他如同php中的composer,centos中的yum,Ubuntu中的apt-get一樣便捷。

  相關(guān)工具可在我的github中找到:cw1997/python-tools,其中easy_install的安裝只須要在python命令行下運行哪個(gè)py腳本之后稍等片刻即可郵箱爬蟲(chóng)軟件,他會(huì )手動(dòng)加入Windows的環(huán)境變量,在Windows命令行下假如輸入easy_install有回顯說(shuō)明安裝成功。

  至于電腦硬件其實(shí)是越快越好,內存至少8G起步,因為爬蟲(chóng)本身須要大量?jì)Υ婧徒馕鲋虚g數據,尤其是多線(xiàn)程爬蟲(chóng),在遇到抓取帶有分頁(yè)的列表和詳情頁(yè),并且抓取數據量很大的情況下使用queue隊列分配抓取任務(wù)會(huì )特別占顯存。包括有的時(shí)候我們抓取的數據是使用json,如果使用mongodb等nosql數據庫儲存,也會(huì )太占顯存。

  網(wǎng)絡(luò )聯(lián)接建議使用有線(xiàn)網(wǎng),因為市面上一些劣質(zhì)的無(wú)線(xiàn)路由器和普通的民用無(wú)線(xiàn)網(wǎng)卡在線(xiàn)程開(kāi)的比較大的情況下會(huì )出現間歇性斷網(wǎng)或則數據遺失,掉包等情況,這個(gè)我親有感受。

  至于操作系統和python其實(shí)肯定是選擇64位。如果你使用的是32位的操作系統,那么難以使用大顯存。如果你使用的是32位的python,可能在小規模抓取數據的時(shí)侯覺(jué)得不出有哪些問(wèn)題,但是當數據量變大的時(shí)侯,比如說(shuō)某個(gè)列表,隊列,字典上面儲存了大量數據,導致python的顯存占用超過(guò)2g的時(shí)侯會(huì )報顯存溢出錯誤。原因在我以前segmentfault上提過(guò)的問(wèn)題中依云的回答有解釋?zhuān)╦ava – python只要占用顯存達到1.9G以后httplib模塊就開(kāi)始報內存溢出錯誤 – SegmentFault)

  如果你打算使用mysql儲存數據,建議使用mysql5.5之后的版本,因為mysql5.5版本支持json數據類(lèi)型,這樣的話(huà)可以?huà)仐塵ongodb了。(有人說(shuō)mysql會(huì )比mongodb穩定一點(diǎn),這個(gè)我不確定。)

  至于現今python都早已出了3.x版本了,為什么我這兒還使用的是python2.7?我個(gè)人選擇2.7版本的緣由是自己當年很早曾經(jīng)買(mǎi)的python核心編程這本書(shū)是第二版的,仍然以2.7為示例版本。并且目前網(wǎng)上一直有大量的教程資料是以2.7為版本講解,2.7在個(gè)別方面與3.x還是有很大差異,如果我們沒(méi)有學(xué)過(guò)2.7,可能對于一些細微的句型差異不是太懂會(huì )導致我們理解上出現誤差,或者看不懂demo代碼。而且如今還是有部份依賴(lài)包只兼容2.7版本。我的建議是假如你是打算急著(zhù)學(xué)python之后去公司工作,并且公司沒(méi)有老代碼須要維護,那么可以考慮直接上手3.x,如果你有比較充沛的時(shí)間,并且沒(méi)有太系統的大牛帶,只能借助網(wǎng)上零零散散的博客文章來(lái)學(xué)習,那么還是先學(xué)2.7在學(xué)3.x,畢竟學(xué)會(huì )了2.7以后3.x上手也很快。

  其實(shí)對于任何軟件項目而言,我們但凡想知道編撰這個(gè)項目須要哪些知識點(diǎn),我們都可以觀(guān)察一下這個(gè)項目的主要入口文件都導出了什么包。

  

  現在來(lái)看一下我們這個(gè)項目,作為一個(gè)剛接觸python的人,可能有一些包幾乎都沒(méi)有用過(guò),那么我們在本小節就來(lái)簡(jiǎn)單的談?wù)勥@種包起哪些作用,要把握她們分別會(huì )涉及到哪些知識點(diǎn),這些知識點(diǎn)的關(guān)鍵詞是哪些。這篇文章并不會(huì )耗費長(cháng)篇大論來(lái)從基礎講起,因此我們要學(xué)會(huì )善用百度,搜索那些知識點(diǎn)的關(guān)鍵詞來(lái)自學(xué)。下面就來(lái)一一剖析一下這種知識點(diǎn)。

  我們的爬蟲(chóng)抓取數據本質(zhì)上就是不停的發(fā)起http請求,獲取http響應,將其存入我們的筆記本中。了解http協(xié)議有助于我們在抓取數據的時(shí)侯對一些才能加速抓取速率的參數才能精準的控制,比如說(shuō)keep-alive等。

  我們平常編撰的程序都是單線(xiàn)程程序,我們寫(xiě)的代碼都在主線(xiàn)程上面運行,這個(gè)主線(xiàn)程又運行在python進(jìn)程中。關(guān)于線(xiàn)程和進(jìn)程的解釋可以參考阮一峰的博客:進(jìn)程與線(xiàn)程的一個(gè)簡(jiǎn)單解釋 – 阮一峰的網(wǎng)路日志

  在python中實(shí)現多線(xiàn)程是通過(guò)一個(gè)名子稱(chēng)作threading的模塊來(lái)實(shí)現。之前還有thread模塊,但是threading對于線(xiàn)程的控制更強,因此我們后來(lái)都改用threading來(lái)實(shí)現多線(xiàn)程編程了。

  關(guān)于threading多線(xiàn)程的一些用法,我認為這篇文章不錯:[python] 專(zhuān)題八.多線(xiàn)程編程之thread和threading 大家可以參考參考。

  簡(jiǎn)單來(lái)說(shuō),使用threading模塊編撰多線(xiàn)程程序,就是先自己定義一個(gè)類(lèi),然后這個(gè)類(lèi)要承繼threading.Thread,并且把每位線(xiàn)程要做的工作代碼講到一個(gè)類(lèi)的run方式中,當然若果線(xiàn)程本身在創(chuàng )建的時(shí)侯假如要做一些初始化工作,那么就要在他的__init__方法中編撰好初始化工作所要執行的代碼,這個(gè)方式如同php,java中的構造方式一樣。

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

  ***我們就要來(lái)講講至關(guān)重要的線(xiàn)程阻塞這個(gè)概念了。當我們詳盡學(xué)習完threading模塊以后,大概就曉得怎樣創(chuàng )建和啟動(dòng)線(xiàn)程了。但是假如我們把線(xiàn)程創(chuàng )建好了,然后調用了start方式,那么我們會(huì )發(fā)覺(jué)似乎整個(gè)程序立刻就結束了,這是如何回事呢?其實(shí)這是因為我們在主線(xiàn)程中只有負責啟動(dòng)子線(xiàn)程的代碼,也就意味著(zhù)主線(xiàn)程只有啟動(dòng)子線(xiàn)程的功能,至于子線(xiàn)程執行的這些代碼,他們本質(zhì)上只是寫(xiě)在類(lèi)上面的一個(gè)方式,并沒(méi)在主線(xiàn)程上面真正去執行他,所以主線(xiàn)程啟動(dòng)完子線(xiàn)程以后他的本職工作就早已全部完成了,已經(jīng)光榮離場(chǎng)了。既然主線(xiàn)程都離場(chǎng)了,那么python進(jìn)程就跟隨結束了,那么其他線(xiàn)程也就沒(méi)有顯存空間繼續執行了。所以我們應當是要使主線(xiàn)程大嬸等到所有的子線(xiàn)程鄙人全部執行完畢再光榮離場(chǎng),那么在線(xiàn)程對象中有哪些方式才能把主線(xiàn)程卡住呢?thread.sleep嘛?這確實(shí)是個(gè)辦法,但是到底應當使主線(xiàn)程sleep多久呢?我們并不能確切曉得執行完一個(gè)任務(wù)要多久時(shí)間,肯定不能用這個(gè)辦法。所以我們這個(gè)時(shí)侯應當上網(wǎng)查詢(xún)一下有哪些辦法才能使子線(xiàn)程“卡住”主線(xiàn)程呢?“卡住”這個(gè)詞似乎很粗俗了,其實(shí)說(shuō)專(zhuān)業(yè)一點(diǎn),應該稱(chēng)作“阻塞”,所以我們可以查詢(xún)“python 子線(xiàn)程阻塞主線(xiàn)程”,如果我們會(huì )正確使用搜索引擎的話(huà),應該會(huì )查到一個(gè)方式稱(chēng)作join(),沒(méi)錯,這個(gè)join()方法就是子線(xiàn)程用于阻塞主線(xiàn)程的方式,當子線(xiàn)程還未執行完畢的時(shí)侯,主線(xiàn)程運行到富含join()方法的這一行都會(huì )卡在那里,直到所有線(xiàn)程都執行完畢才能執行join()方法前面的代碼。

  假設有一個(gè)這樣的場(chǎng)景,我們須要抓取一個(gè)人的博客,我們曉得這個(gè)人的博客有兩個(gè)頁(yè)面,一個(gè)list.php頁(yè)面顯示的是此博客的所有文章鏈接,還有一個(gè)view.php頁(yè)面顯示的是一篇文章的具體內容。

  如果我們要把這個(gè)人的博客上面所有文章內容抓取出來(lái),編寫(xiě)單線(xiàn)程爬蟲(chóng)的思路是:先用正則表達式把這個(gè)list.php頁(yè)面的所有鏈接a標簽的href屬性抓取出來(lái),存入一個(gè)名子稱(chēng)作article_list的鏈表(在python中不叫鏈表,叫做list,中文名列表),然后再用一個(gè)for循環(huán)遍歷這個(gè)article_list鏈表,用各類(lèi)抓取網(wǎng)頁(yè)內容的函數把內容抓取出來(lái)之后存入數據庫。

  如果我們要編撰一個(gè)多線(xiàn)程爬蟲(chóng)來(lái)完成這個(gè)任務(wù)的話(huà),就假定我們的程序用10個(gè)線(xiàn)程把,那么我們就要想辦法把之前抓取的article_list平均分成10份,分別把每一份分配給其中一個(gè)子線(xiàn)程。

  但是問(wèn)題來(lái)了,如果我們的article_list鏈表寬度不是10的倍數,也就是文章數量并不是10的整數倍,那么***一個(gè)線(xiàn)程都會(huì )比別的線(xiàn)程少分配到一些任務(wù),那么它將會(huì )更快的結束。

  如果僅僅是抓取這些只有幾千字的博客文章這看似沒(méi)哪些問(wèn)題,但是假如我們一個(gè)任務(wù)(不一定是抓取網(wǎng)頁(yè)的任務(wù),有可能是物理估算,或者圖形渲染等等歷時(shí)任務(wù))的運行時(shí)間太長(cháng),那么這將導致極大地資源和時(shí)間浪費。我們多線(xiàn)程的目的就是盡可能的借助一切估算資源而且估算時(shí)間,所以我們要想辦法使任務(wù)才能愈發(fā)科學(xué)合理的分配。

  并且我還要考慮一種情況,就是文章數量很大的情況下,我們要既能快速抓取到文章內容,又能盡早的看見(jiàn)我們早已抓取到的內容,這種需求在好多CMS采集站上常常會(huì )彰顯下來(lái)。

  比如說(shuō)我們如今要抓取的目標博客,有幾千萬(wàn)篇文章,通常這些情況下博客還會(huì )做分頁(yè)處理,那么我們若果根據前面的傳統思路先抓取完list.php的所有頁(yè)面至少就要幾個(gè)小時(shí)甚至幾天,老板假如希望你還能早日顯示出抓取內容,并且盡早將早已抓取到的內容詮釋到我們的CMS采集站上,那么我們就要實(shí)現一邊抓取list.php而且把早已抓取到的數據丟入一個(gè)article_list鏈表,一邊用另一個(gè)線(xiàn)程從article_list鏈表中提取早已抓取到的文章URL地址,然后這個(gè)線(xiàn)程再去對應的URL地址中用正則表達式取到博客文章內容。如何實(shí)現這個(gè)功能呢?

  我們就須要同時(shí)開(kāi)啟兩類(lèi)線(xiàn)程,一類(lèi)線(xiàn)程專(zhuān)門(mén)負責抓取list.php中的url之后丟入article_list鏈表,另外一類(lèi)線(xiàn)程專(zhuān)門(mén)負責從article_list中提取出url之后從對應的view.php頁(yè)面中抓取出對應的博客內容。

  但是我們是否還記得上面提及過(guò)線(xiàn)程安全這個(gè)概念?前一類(lèi)線(xiàn)程一邊往article_list字段中寫(xiě)入數據,另外那一類(lèi)的線(xiàn)程從article_list中讀取數據但是刪掉早已讀取完畢的數據。但是python中list并不是線(xiàn)程安全版本的數據結構,因此這樣操作會(huì )導致不可預想的錯誤。所以我們可以嘗試使用一個(gè)愈發(fā)便捷且線(xiàn)程安全的數據結構,這就是我們的子標題中所提及的Queue隊列數據結構。

  同樣Queue也有一個(gè)join()方法,這個(gè)join()方法雖然和上一個(gè)小節所提到的threading中join()方法差不多,只不過(guò)在Queue中,join()的阻塞條件是當隊列不為空空的時(shí)侯才阻塞,否則繼續執行join()后面的代碼。在這個(gè)爬蟲(chóng)中我便使用了這些技巧來(lái)阻塞主線(xiàn)程而不是直接通過(guò)線(xiàn)程的join方法來(lái)阻塞主線(xiàn)程,這樣的用處是可以不用寫(xiě)一個(gè)死循環(huán)來(lái)判定當前任務(wù)隊列中是否還有未執行完的任務(wù),讓程序運行愈發(fā)高效,也使代碼愈發(fā)柔美。

  還有一個(gè)細節就是在python2.7中隊列模塊的名子是Queue,而在python3.x中早已更名為queue,就是首字母大小寫(xiě)的區別,大家假如是復制網(wǎng)上的代碼,要記得這個(gè)小區別。

  如果你們學(xué)過(guò)c語(yǔ)言的話(huà),對這個(gè)模塊應當會(huì )太熟悉,他就是一個(gè)負責從命令行中的命令上面提取出附送參數的模塊。比如說(shuō)我們一般在命令行中操作mysql數據庫,就是輸入mysql -h127.0.0.1 -uroot -p,其中mysql前面的“-h127.0.0.1 -uroot -p”就是可以獲取的參數部份。

  我們平常在編撰爬蟲(chóng)的時(shí)侯,有一些參數是須要用戶(hù)自己自動(dòng)輸入的,比如說(shuō)mysql的主機IP,用戶(hù)名密碼等等。為了使我們的程序愈加友好通用,有一些配置項是不需要硬編碼在代碼上面,而是在執行他的時(shí)侯我們動(dòng)態(tài)傳入,結合getopt模塊我們就可以實(shí)現這個(gè)功能。

  哈希本質(zhì)上就是一類(lèi)物理算法的集合,這種物理算法有個(gè)特點(diǎn)就是你給定一個(gè)參數,他就能輸出另外一個(gè)結果,雖然這個(gè)結果太短,但是他可以近似覺(jué)得是***的。比如說(shuō)我們平常聽(tīng)過(guò)的md5,sha-1等等,他們都屬于哈希算法。他們可以把一些文件,文字經(jīng)過(guò)一系列的物理運算然后弄成短短不到一百位的一段數字中文混和的字符串。

  python中的hashlib模塊就為我們封裝好了這種物理運算函數,我們只須要簡(jiǎn)單的調用它就可以完成哈希運算。

  為什么在我這個(gè)爬蟲(chóng)中用到了這個(gè)包呢?因為在一些插口懇求中,服務(wù)器須要帶上一些校驗碼,保證插口懇求的數據沒(méi)有被篡改或則遺失,這些校驗碼通常都是hash算法,所以我們須要用到這個(gè)模塊來(lái)完成這些運算。

  很多時(shí)侯我們抓取到的數據不是html,而是一些json數據,json本質(zhì)上只是一段富含通配符對的字符串,如果我們須要提取出其中特定的字符串,那么我們須要json這個(gè)模塊來(lái)將這個(gè)json字符串轉換為dict類(lèi)型便捷我們操作。

  有的時(shí)侯我們抓取到了一些網(wǎng)頁(yè)內容,但是我們須要將網(wǎng)頁(yè)中的一些特定格式的內容提取下來(lái),比如說(shuō)電子郵箱的格式通常都是上面幾位英語(yǔ)數字字母加一個(gè)@符號加的域名,而要象計算機語(yǔ)言描述這些格式,我們可以使用一種稱(chēng)作正則表達式的表達式來(lái)抒發(fā)出這些格式,并且使計算機手動(dòng)從一大段字符串上將符合這些特定格式的文字匹配下來(lái)。

  這個(gè)模塊主要用于處理一些系統方面的事情,在這個(gè)爬蟲(chóng)中我用他來(lái)解決輸出編碼問(wèn)題。

  稍微學(xué)過(guò)一點(diǎn)法語(yǔ)的人都還能猜下來(lái)這個(gè)模塊用于處理時(shí)間,在這個(gè)爬蟲(chóng)中我用它來(lái)獲取當前時(shí)間戳,然后通過(guò)在主線(xiàn)程末尾用當前時(shí)間戳除以程序開(kāi)始運行時(shí)的時(shí)間戳,得到程序的運行時(shí)間。

  

  如圖所示,開(kāi)50個(gè)線(xiàn)程抓取100頁(yè)(每頁(yè)30個(gè)貼子,相當于抓取了3000個(gè)貼子)貼吧貼子內容而且從中提取出手機郵箱這個(gè)步驟共歷時(shí)330秒。

  這兩個(gè)模塊都是用于處理一些http請求,以及url低格方面的事情。我的爬蟲(chóng)http請求部份的核心代碼就是使用這個(gè)模塊完成的。

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

  這里我們要注意一個(gè)細節問(wèn)題:mysqldb模塊并不是線(xiàn)程安全版本,意味著(zhù)我們不能在多線(xiàn)程中共享同一個(gè)mysql聯(lián)接句柄。所以你們可以在我的代碼中聽(tīng)到,我在每位線(xiàn)程的構造函數中都傳入了一個(gè)新的mysql聯(lián)接句柄。因此每位子線(xiàn)程只會(huì )用自己獨立的mysql聯(lián)接句柄。

  這也是一個(gè)第三方模塊,網(wǎng)上還能找到相關(guān)代碼,這個(gè)模塊主要用于向命令行中輸出彩色字符串。比如說(shuō)我們一般爬蟲(chóng)出現錯誤,要輸出*敏*感*詞*的字體會(huì )比較醒目,就要使用到這個(gè)模塊。

  

  如果你們在網(wǎng)路質(zhì)量不是挺好的環(huán)境下使用該爬蟲(chóng),會(huì )發(fā)覺(jué)有的時(shí)侯會(huì )報如圖所示的異常,這是我為了偷懶并沒(méi)有寫(xiě)各類(lèi)異常處理的邏輯。

  通常情況下我們假如要編撰高度自動(dòng)化的爬蟲(chóng),那么就須要意料到我們的爬蟲(chóng)可能會(huì )遇見(jiàn)的所有異常情況郵箱爬蟲(chóng)軟件,針對這種異常情況做處理。

  比如說(shuō)如圖所示的錯誤,我們就應當把當時(shí)正在處理的任務(wù)重新伸入任務(wù)隊列,否則我們還會(huì )出現遺漏信息的情況。這也是爬蟲(chóng)編撰的一個(gè)復雜點(diǎn)。

  其實(shí)多線(xiàn)程爬蟲(chóng)的編撰也不復雜,多看示例代碼,多自己動(dòng)手嘗試,多去社區,論壇交流,很多精典的書(shū)上對多線(xiàn)程編程也有特別詳盡的解釋。這篇文章本質(zhì)上主要還是一篇科普文章,內容講解的都不是太深入,大家還須要課外自己多結合網(wǎng)上各類(lèi)資料自己學(xué)習。

  【編輯推薦】

  Python程序員都該用的一個(gè)庫Python正則表達式re模塊簡(jiǎn)明筆記這種方式推動(dòng)Python開(kāi)發(fā)者提升效率Python并發(fā)編程之線(xiàn)程池/進(jìn)程池Python黑魔法之描述符

0 個(gè)評論

要回復文章請先登錄注冊


官方客服QQ群

微信人工客服

QQ人工客服


線(xiàn)

亚洲国产精品无码久久大片,亚洲AV无码乱码麻豆精品国产,亚洲品质自拍网站,少妇伦子伦精品无码STYLES,国产精久久久久久久