『壹』 如何用python做爬蟲
1)首先你要明白爬蟲怎樣工作。
想像你是一隻蜘蛛,現在你被放到了互聯「網」上。那麼,你需要把所有的網頁都看一遍。怎麼辦呢?沒問題呀,你就隨便從某個地方開始,比如說人民日報的首頁,這個叫initial pages,用$表示吧。
在人民日報的首頁,你看到那個頁面引向的各種鏈接。於是你很開心地從爬到了「國內新聞」那個頁面。太好了,這樣你就已經爬完了倆頁面(首頁和國內新聞)!暫且不用管爬下來的頁面怎麼處理的,你就想像你把這個頁面完完整整抄成了個html放到了你身上。
突然你發現, 在國內新聞這個頁面上,有一個鏈接鏈回「首頁」。作為一隻聰明的蜘蛛,你肯定知道你不用爬回去的吧,因為你已經看過了啊。所以,你需要用你的腦子,存下你已經看過的頁面地址。這樣,每次看到一個可能需要爬的新鏈接,你就先查查你腦子里是不是已經去過這個頁面地址。如果去過,那就別去了。
好的,理論上如果所有的頁面可以從initial page達到的話,那麼可以證明你一定可以爬完所有的網頁。
那麼在python里怎麼實現呢?
很簡單
import Queue
initial_page = "初始化頁"
url_queue = Queue.Queue()
seen = set()
seen.insert(initial_page)
url_queue.put(initial_page)
while(True): #一直進行直到海枯石爛
if url_queue.size()>0:
current_url = url_queue.get() #拿出隊例中第一個的url
store(current_url) #把這個url代表的網頁存儲好
for next_url in extract_urls(current_url): #提取把這個url里鏈向的url
if next_url not in seen:
seen.put(next_url)
url_queue.put(next_url)
else:
break
寫得已經很偽代碼了。
所有的爬蟲的backbone都在這里,下面分析一下為什麼爬蟲事實上是個非常復雜的東西——搜索引擎公司通常有一整個團隊來維護和開發。
2)效率
如果你直接加工一下上面的代碼直接運行的話,你需要一整年才能爬下整個豆瓣的內容。更別說Google這樣的搜索引擎需要爬下全網的內容了。
問題出在哪呢?需要爬的網頁實在太多太多了,而上面的代碼太慢太慢了。設想全網有N個網站,那麼分析一下判重的復雜度就是N*log(N),因為所有網頁要遍歷一次,而每次判重用set的話需要log(N)的復雜度。OK,OK,我知道python的set實現是hash——不過這樣還是太慢了,至少內存使用效率不高。
通常的判重做法是怎樣呢?Bloom Filter. 簡單講它仍然是一種hash的方法,但是它的特點是,它可以使用固定的內存(不隨url的數量而增長)以O(1)的效率判定url是否已經在set中。可惜天下沒有白吃的午餐,它的唯一問題在於,如果這個url不在set中,BF可以100%確定這個url沒有看過。但是如果這個url在set中,它會告訴你:這個url應該已經出現過,不過我有2%的不確定性。注意這里的不確定性在你分配的內存足夠大的時候,可以變得很小很少。一個簡單的教程:Bloom Filters by Example
注意到這個特點,url如果被看過,那麼可能以小概率重復看一看(沒關系,多看看不會累死)。但是如果沒被看過,一定會被看一下(這個很重要,不然我們就要漏掉一些網頁了!)。 [IMPORTANT: 此段有問題,請暫時略過]
好,現在已經接近處理判重最快的方法了。另外一個瓶頸——你只有一台機器。不管你的帶寬有多大,只要你的機器下載網頁的速度是瓶頸的話,那麼你只有加快這個速度。用一台機子不夠的話——用很多台吧!當然,我們假設每台機子都已經進了最大的效率——使用多線程(python的話,多進程吧)。
3)集群化抓取
爬取豆瓣的時候,我總共用了100多台機器晝夜不停地運行了一個月。想像如果只用一台機子你就得運行100個月了...
那麼,假設你現在有100台機器可以用,怎麼用python實現一個分布式的爬取演算法呢?
我們把這100台中的99台運算能力較小的機器叫作slave,另外一台較大的機器叫作master,那麼回顧上面代碼中的url_queue,如果我們能把這個queue放到這台master機器上,所有的slave都可以通過網路跟master聯通,每當一個slave完成下載一個網頁,就向master請求一個新的網頁來抓取。而每次slave新抓到一個網頁,就把這個網頁上所有的鏈接送到master的queue里去。同樣,bloom filter也放到master上,但是現在master只發送確定沒有被訪問過的url給slave。Bloom Filter放到master的內存里,而被訪問過的url放到運行在master上的Redis里,這樣保證所有操作都是O(1)。(至少平攤是O(1),Redis的訪問效率見:LINSERT – Redis)
考慮如何用python實現:
在各台slave上裝好scrapy,那麼各台機子就變成了一台有抓取能力的slave,在master上裝好Redis和rq用作分布式隊列。
代碼於是寫成
#slave.py
current_url = request_from_master()
to_send = []
for next_url in extract_urls(current_url):
to_send.append(next_url)
store(current_url);
send_to_master(to_send)
#master.py
distributed_queue = DistributedQueue()
bf = BloomFilter()
initial_pages = "www.renmingribao.com"
while(True):
if request == 'GET':
if distributed_queue.size()>0:
send(distributed_queue.get())
else:
break
elif request == 'POST':
bf.put(request.url)
好的,其實你能想到,有人已經給你寫好了你需要的:darkrho/scrapy-redis · GitHub
4)展望及後處理
雖然上面用很多「簡單」,但是真正要實現一個商業規模可用的爬蟲並不是一件容易的事。上面的代碼用來爬一個整體的網站幾乎沒有太大的問題。
但是如果附加上你需要這些後續處理,比如
有效地存儲(資料庫應該怎樣安排)
有效地判重(這里指網頁判重,咱可不想把人民日報和抄襲它的大民日報都爬一遍)
有效地信息抽取(比如怎麼樣抽取出網頁上所有的地址抽取出來,「朝陽區奮進路中華道」),搜索引擎通常不需要存儲所有的信息,比如圖片我存來幹嘛...
及時更新(預測這個網頁多久會更新一次)
如你所想,這里每一個點都可以供很多研究者十數年的研究。雖然如此,
「路漫漫其修遠兮,吾將上下而求索」。
所以,不要問怎麼入門,直接上路就好了:)
『貳』 如何用python寫出爬蟲
先檢查是否有API
API是網站官方提供的數據介面,如果通過調用API採集數據,則相當於在網站允許的范圍內採集,這樣既不會有道德法律風險,也沒有網站故意設置的障礙;不過調用API介面的訪問則處於網站的控制中,網站可以用來收費,可以用來限制訪問上限等。整體來看,如果數據採集的需求並不是很獨特,那麼有API則應優先採用調用API的方式。
數據結構分析和數據存儲
爬蟲需求要十分清晰,具體表現為需要哪些欄位,這些欄位可以是網頁上現有的,也可以是根據網頁上現有的欄位進一步計算的,這些欄位如何構建表,多張表如何連接等。值得一提的是,確定欄位環節,不要只看少量的網頁,因為單個網頁可以缺少別的同類網頁的欄位,這既有可能是由於網站的問題,也可能是用戶行為的差異,只有多觀察一些網頁才能綜合抽象出具有普適性的關鍵欄位——這並不是幾分鍾看幾個網頁就可以決定的簡單事情,如果遇上了那種臃腫、混亂的網站,可能坑非常多。
對於大規模爬蟲,除了本身要採集的數據外,其他重要的中間數據(比如頁面Id或者url)也建議存儲下來,這樣可以不必每次重新爬取id。
資料庫並沒有固定的選擇,本質仍是將Python里的數據寫到庫里,可以選擇關系型資料庫MySQL等,也可以選擇非關系型資料庫MongoDB等;對於普通的結構化數據一般存在關系型資料庫即可。sqlalchemy是一個成熟好用的資料庫連接框架,其引擎可與Pandas配套使用,把數據處理和數據存儲連接起來,一氣呵成。
數據流分析
對於要批量爬取的網頁,往上一層,看它的入口在哪裡;這個是根據採集范圍來確定入口,比如若只想爬一個地區的數據,那從該地區的主頁切入即可;但若想爬全國數據,則應更往上一層,從全國的入口切入。一般的網站網頁都以樹狀結構為主,找到切入點作為根節點一層層往裡進入即可。
值得注意的一點是,一般網站都不會直接把全量的數據做成列表給你一頁頁往下翻直到遍歷完數據,比如鏈家上面很清楚地寫著有24587套二手房,但是它只給100頁,每頁30個,如果直接這么切入只能訪問3000個,遠遠低於真實數據量;因此先切片,再整合的數據思維可以獲得更大的數據量。顯然100頁是系統設定,只要超過300個就只顯示100頁,因此可以通過其他的篩選條件不斷細分,只到篩選結果小於等於300頁就表示該條件下沒有缺漏;最後把各種條件下的篩選結果集合在一起,就能夠盡可能地還原真實數據量。
明確了大規模爬蟲的數據流動機制,下一步就是針對單個網頁進行解析,然後把這個模式復制到整體。對於單個網頁,採用抓包工具可以查看它的請求方式,是get還是post,有沒有提交表單,欲採集的數據是寫入源代碼里還是通過AJAX調用JSON數據。
同樣的道理,不能只看一個頁面,要觀察多個頁面,因為批量爬蟲要弄清這些大量頁面url以及參數的規律,以便可以自動構造;有的網站的url以及關鍵參數是加密的,這樣就悲劇了,不能靠著明顯的邏輯直接構造,這種情況下要批量爬蟲,要麼找到它加密的js代碼,在爬蟲代碼上加入從明文到密碼的加密過程;要麼採用下文所述的模擬瀏覽器的方式。
數據採集
之前用R做爬蟲,不要笑,R的確可以做爬蟲工作;但在爬蟲方面,Python顯然優勢更明顯,受眾更廣,這得益於其成熟的爬蟲框架,以及其他的在計算機系統上更好的性能。scrapy是一個成熟的爬蟲框架,直接往裡套用就好,比較適合新手學習;requests是一個比原生的urllib包更簡潔強大的包,適合作定製化的爬蟲功能。requests主要提供一個基本訪問功能,把網頁的源代碼給download下來。一般而言,只要加上跟瀏覽器同樣的Requests Headers參數,就可以正常訪問,status_code為200,並成功得到網頁源代碼;但是也有某些反爬蟲較為嚴格的網站,這么直接訪問會被禁止;或者說status為200也不會返回正常的網頁源碼,而是要求寫驗證碼的js腳本等。
下載到了源碼之後,如果數據就在源碼中,這種情況是最簡單的,這就表示已經成功獲取到了數據,剩下的無非就是數據提取、清洗、入庫。但若網頁上有,然而源代碼里沒有的,就表示數據寫在其他地方,一般而言是通過AJAX非同步載入JSON數據,從XHR中找即可找到;如果這樣還找不到,那就需要去解析js腳本了。
解析工具
源碼下載後,就是解析數據了,常用的有兩種方法,一種是用BeautifulSoup對樹狀HTML進行解析,另一種是通過正則表達式從文本中抽取數據。
BeautifulSoup比較簡單,支持Xpath和CSSSelector兩種途徑,而且像Chrome這類瀏覽器一般都已經把各個結點的Xpath或者CSSSelector標記好了,直接復制即可。以CSSSelector為例,可以選擇tag、id、class等多種方式進行定位選擇,如果有id建議選id,因為根據HTML語法,一個id只能綁定一個標簽。
正則表達式很強大,但構造起來有點復雜,需要專門去學習。因為下載下來的源碼格式就是字元串,所以正則表達式可以大顯身手,而且處理速度很快。
對於HTML結構固定,即同樣的欄位處tag、id和class名稱都相同,採用BeautifulSoup解析是一種簡單高效的方案,但有的網站混亂,同樣的數據在不同頁面間HTML結構不同,這種情況下BeautifulSoup就不太好使;如果數據本身格式固定,則用正則表達式更方便。比如以下的例子,這兩個都是深圳地區某個地方的經度,但一個頁面的class是long,一個頁面的class是longitude,根據class來選擇就沒辦法同時滿足2個,但只要注意到深圳地區的經度都是介於113到114之間的浮點數,就可以通過正則表達式"11[3-4].\d+"來使兩個都滿足。
數據整理
一般而言,爬下來的原始數據都不是清潔的,所以在入庫前要先整理;由於大部分都是字元串,所以主要也就是字元串的處理方式了。
字元串自帶的方法可以滿足大部分簡單的處理需求,比如strip可以去掉首尾不需要的字元或者換行符等,replace可以將指定部分替換成需要的部分,split可以在指定部分分割然後截取一部分。
如果字元串處理的需求太復雜以致常規的字元串處理方法不好解決,那就要請出正則表達式這個大殺器。
Pandas是Python中常用的數據處理模塊,雖然作為一個從R轉過來的人一直覺得這個模仿R的包實在是太難用了。Pandas不僅可以進行向量化處理、篩選、分組、計算,還能夠整合成DataFrame,將採集的數據整合成一張表,呈現最終的存儲效果。
寫入資料庫
如果只是中小規模的爬蟲,可以把最後的爬蟲結果匯合成一張表,最後導出成一張表格以便後續使用;但對於表數量多、單張表容量大的大規模爬蟲,再導出成一堆零散的表就不合適了,肯定還是要放在資料庫中,既方便存儲,也方便進一步整理。
寫入資料庫有兩種方法,一種是通過Pandas的DataFrame自帶的to_sql方法,好處是自動建表,對於對表結構沒有嚴格要求的情況下可以採用這種方式,不過值得一提的是,如果是多行的DataFrame可以直接插入不加索引,但若只有一行就要加索引否則報錯,雖然這個認為不太合理;另一種是利用資料庫引擎來執行SQL語句,這種情況下要先自己建表,雖然多了一步,但是表結構完全是自己控制之下。Pandas與SQL都可以用來建表、整理數據,結合起來使用效率更高。
『叄』 python爬蟲可以自學嗎
無論是從入門級選手到專業級選手都在做的爬蟲,還是Web 程序開發、桌面程序開發,又或者是科學計算、圖像處理,Python編程都可以勝任。或許是因為這種屬性,周圍好多小夥伴都開始學習Python。Python爬蟲可以自學嗎?(推薦學習:Python視頻教程)
可以的,世上無難事只怕有心人。只要你下定決心,把下面的書籍吃透,動手實踐,相信你的爬蟲技術一定ok。
Python是一種代表簡單主義思想的語言。閱讀一個良好的Python程序就感覺像是在讀英語一樣。它使你能夠專注於解決問題而不是去搞明白語言本身。
Python極其容易上手,因為Python有極其簡單的說明文檔
1、如果你用Python3寫爬蟲,強力推薦《Python網路數據採集》這本書,應該是目前最系統最完善介紹Python爬蟲的書。可以去圖靈社區買電子版。
書的內容很新也很系統,從beautifulSoup,requests到ajax,圖像識別,單元測試。比起絕大多數blog零散的教程要好的多,看完書後就可以去做些實戰項目,這個時候可以去github上找類似的項目借鑒下。
2、國內也有一本講爬蟲的好書,《自己動手寫網路爬蟲》,這本書除了介紹爬蟲基本原理,包括優先順序,寬度優先搜索,分布式爬蟲,多線程,還有雲計算,數據挖掘內容。只不過用了java來實現,但思路是相同的。
Python爬蟲靠系統學習固然好,直接寫一個項目出來效果更加簡單粗暴!(不過自己現在的水平寫出來都是流水一般的面向過程的代碼,代碼的重復部分太多,正在回過頭去學習面向對象編程,學習類和方法的使用。不過,我還是堅定地認為:入門的時候,應該直接簡單粗暴地實踐一個項目。
3、哪裡不會搜哪裡!哪裡報錯改哪裡!相信我你遇到的99%的問題都能從網上找到相似的問題,你需要做的就是寫代碼!搜問題!調BUG!你搜不到解決辦法的情況下,80%的情況是你搜索的姿勢不對,另外20%可能需要你自己動動腦子,換個思路去做。
目前在IT行業里,技術是在新月異的更新中,不斷換代升級,Python行業更是如此。而我們知道,在學校所學專業知識可能很難滿足如今的社會需求。
說了這么多,要是現在的情況不適合你進行自學,或許是你的自製力不夠,或許是你沒有足夠多的時間自學,或許你需要更專業的課程學習,相信專業的課程學習能帶給你更多東西,相信你會收獲更多的友誼和人脈資源。
更多Python相關技術文章,請訪問Python教程欄目進行學習!以上就是小編分享的關於python爬蟲可以自學嗎的詳細內容希望對大家有所幫助,更多有關python教程請關注環球青藤其它相關文章!
『肆』 Python編程基礎之(五)Scrapy爬蟲框架
經過前面四章的學習,我們已經可以使用Requests庫、Beautiful Soup庫和Re庫,編寫基本的Python爬蟲程序了。那麼這一章就來學習一個專業的網路爬蟲框架--Scrapy。沒錯,是框架,而不是像前面介紹的函數功能庫。
Scrapy是一個快速、功能強大的網路爬蟲框架。
可能大家還不太了解什麼是框架,爬蟲框架其實是實現爬蟲功能的一個軟體結構和功能組件的集合。
簡而言之, Scrapy就是一個爬蟲程序的半成品,可以幫助用戶實現專業的網路爬蟲。
使用Scrapy框架,不需要你編寫大量的代碼,Scrapy已經把大部分工作都做好了,允許你調用幾句代碼便自動生成爬蟲程序,可以節省大量的時間。
當然,框架所生成的代碼基本是一致的,如果遇到一些特定的爬蟲任務時,就不如自己使用Requests庫搭建來的方便了。
PyCharm安裝
測試安裝:
出現框架版本說明安裝成功。
掌握Scrapy爬蟲框架的結構是使用好Scrapy的重中之重!
先上圖:
整個結構可以簡單地概括為: 「5+2」結構和3條數據流
5個主要模塊(及功能):
(1)控制所有模塊之間的數據流。
(2)可以根據條件觸發事件。
(1)根據請求下載網頁。
(1)對所有爬取請求進行調度管理。
(1)解析DOWNLOADER返回的響應--response。
(2)產生爬取項--scraped item。
(3)產生額外的爬取請求--request。
(1)以流水線方式處理SPIDER產生的爬取項。
(2)由一組操作順序組成,類似流水線,每個操作是一個ITEM PIPELINES類型。
(3)清理、檢查和查重爬取項中的HTML數據並將數據存儲到資料庫中。
2個中間鍵:
(1)對Engine、Scheler、Downloader之間進行用戶可配置的控制。
(2)修改、丟棄、新增請求或響應。
(1)對請求和爬取項進行再處理。
(2)修改、丟棄、新增請求或爬取項。
3條數據流:
(1):圖中數字 1-2
1:Engine從Spider處獲得爬取請求--request。
2:Engine將爬取請求轉發給Scheler,用於調度。
(2):圖中數字 3-4-5-6
3:Engine從Scheler處獲得下一個要爬取的請求。
4:Engine將爬取請求通過中間件發送給Downloader。
5:爬取網頁後,Downloader形成響應--response,通過中間件發送給Engine。
6:Engine將收到的響應通過中間件發送給Spider處理。
(3):圖中數字 7-8-9
7:Spider處理響應後產生爬取項--scraped item。
8:Engine將爬取項發送給Item Pipelines。
9:Engine將爬取請求發送給Scheler。
任務處理流程:從Spider的初始爬取請求開始爬取,Engine控制各模塊數據流,不間斷從Scheler處獲得爬取請求,直至請求為空,最後到Item Pipelines存儲數據結束。
作為用戶,只需配置好Scrapy框架的Spider和Item Pipelines,也就是數據流的入口與出口,便可完成一個爬蟲程序的搭建。Scrapy提供了簡單的爬蟲命令語句,幫助用戶一鍵配置剩餘文件,那我們便來看看有哪些好用的命令吧。
Scrapy採用命令行創建和運行爬蟲
PyCharm打開Terminal,啟動Scrapy:
Scrapy基本命令行格式:
具體常用命令如下:
下面用一個例子來學習一下命令的使用:
1.建立一個Scrapy爬蟲工程,在已啟動的Scrapy中繼續輸入:
執行該命令,系統會在PyCharm的工程文件中自動創建一個工程,命名為pythonDemo。
2.產生一個Scrapy爬蟲,以教育部網站為例http://www.moe.gov.cn:
命令生成了一個名為demo的spider,並在Spiders目錄下生成文件demo.py。
命令僅用於生成demo.py文件,該文件也可以手動生成。
觀察一下demo.py文件:
3.配置產生的spider爬蟲,也就是demo.py文件:
4.運行爬蟲,爬取網頁:
如果爬取成功,會發現在pythonDemo下多了一個t20210816_551472.html的文件,我們所爬取的網頁內容都已經寫入該文件了。
以上就是Scrapy框架的簡單使用了。
Request對象表示一個HTTP請求,由Spider生成,由Downloader執行。
Response對象表示一個HTTP響應,由Downloader生成,有Spider處理。
Item對象表示一個從HTML頁面中提取的信息內容,由Spider生成,由Item Pipelines處理。Item類似於字典類型,可以按照字典類型來操作。
『伍』 python爬蟲簡單代碼怎麼寫
import requests
import you_get
# 系統模塊包
import sys
import json
url = '視頻的播放地址'
path = './shipin'
def downloadshipin(url,path):
'''
#:param url: 視頻播放的地址
#:param path: 視頻下載保存的路徑
#:return:
'''
# 調用cmd指令
sys.argv = ['you_get','-o',path,url]
you_get.main()
def Extractshipin():
'''
提取網頁當中的視頻播放地址
:return:
'''
urls = ''
headers = {
'user-agent':''
}
response = requests.get(urls,headers=headers).text
json_data = json.loads(response[37:-1])
data = json_data['result']
for i in data:
shipin_url = i['arcurl']
path = './shipin'
downloadshipin(shipin_url,path)
Extractshipin()
『陸』 如何用Python做爬蟲
在我們日常上網瀏覽網頁的時候,經常會看到一些好看的圖片,我們就希望把這些圖片保存下載,或者用戶用來做桌面壁紙,或者用來做設計的素材。
我們最常規的做法就是通過滑鼠右鍵,選擇另存為。但有些圖片滑鼠右鍵的時候並沒有另存為選項,還有辦法就通過就是通過截圖工具截取下來,但這樣就降低圖片的清晰度。好吧其實你很厲害的,右鍵查看頁面源代碼。
我們可以通過python來實現這樣一個簡單的爬蟲功能,把我們想要的代碼爬取到本地。下面就看看如何使用python來實現這樣一個功能。
『柒』 Python 爬蟲的入門教程有哪些值得推薦的
Python 爬蟲的入門教程有很多值得推薦的,以下是一些比較受歡迎和推薦的教程:
1.《精通 Python 網路爬蟲》:這本書是一本入門級的 Python 爬蟲教程,適合初學者學習。
Python3 網路爬蟲實戰:這是一個在線教程,詳細介紹了 Python 爬蟲的基礎知識,包括爬蟲的原理、如何使用 Python 爬取網頁、如何使用正則表達式和 XPath 解析網頁等。
Python 爬蟲指南:這是一個在線教程,通過幾個簡單的例子來介紹 Python 爬蟲的基礎知識。
網路爬蟲實戰:這是一個在線課程,通過幾個實際案例來介紹 Python 爬蟲的基礎知識和進階技巧。
Python 爬蟲實戰:這是一個在線課程,通過幾個實際案例來介紹 Python 爬蟲的基礎知識和進階技巧。
以上是一些比較受歡迎和推薦的 Python 爬蟲入門教程,你可以根據自己的需求和學習進度選擇適合自己的教程。
bilibili上也有一些視頻教程。
『捌』 如何用Python寫一個分布式爬蟲
本文將會以PC端微博進行講解,因為移動端微博數據不如PC短全面,而且抓取和解析難度都會小一些。文章比較長,由於篇幅所限,文章並沒有列出所有代碼,只是講了大致流程和思路。
要抓微博數據,第一步便是模擬登陸,因為很多信息(比如用戶信息,用戶主頁微博數據翻頁等各種翻頁)都需要在登錄狀態下才能查看。關於模擬登陸進階,我寫過兩篇文章,一篇是模擬登陸微博的,是從小白的角度寫的。另外一篇是模擬登陸網路雲的,是從有一定經驗的熟手的角度寫的。讀了這兩篇文章,並且根據我寫的過程自己動手實現過的同學,應該對於模擬登陸PC端微博是沒有太大難度的。那兩篇文章沒有講如何處理驗證碼,這里我簡單說一下,做爬蟲的同學不要老想著用什麼機器學習的方法去識別復雜驗證碼,真的難度非常大,這應該也不是一個爬蟲工程師的工作重點,當然這只是我的個人建議。工程化的項目,我還是建議大家通過打碼平台來解決驗證碼的問題。我在分布式微博爬蟲中就是直接調用打碼平台的介面來做的大規模微博賬號的模擬登陸,效果還不錯,而且打碼成本很低。
說完模擬登陸(具體請參見我寫的那兩篇文章,篇幅所限,我就不過來了),我們現在正式進入微博的數據抓取。這里我會以微博用戶信息抓取為例來進行分析和講解。
關於用戶信息抓取,可能我們有兩個目的。一個是我們只想抓一些指定用戶,另外一個是我們想盡可能多的抓取更多數量的用戶的信息。我的目的假定是第二種。那麼我們該以什麼樣的策略來抓取,才能獲得盡可能多的用戶信息呢?如果我們初始用戶選擇有誤,選了一些不活躍的用戶,很可能會形成一個環,這樣就抓不了太多的數據。這里有一個很簡單的思路:我們把一些大V拿來做為種子用戶,我們先抓他們的個人信息,然後再抓大V所關注的用戶和粉絲,大V關注的用戶肯定也是類似大V的用戶,這樣的話,就不容易形成環了。
策略我們都清楚了。就該是分析和編碼了。
我們先來分析如何構造用戶信息的URL。這里我以微博名為一起神吐槽的博主為例進行分析。做爬蟲的話,一個很重要的意識就是爬蟲能抓的數據都是人能看到的數據,反過來,人能在瀏覽器上看到的數據,爬蟲幾乎都能抓。這里用的是幾乎,因為有的數據抓取難度特別。我們首先需要以正常人的流程看看怎麼獲取到用戶的信息。我們先進入該博主的主頁,如下圖
根據唯一性判斷
我們在頁面源碼中搜索,只發現一個script中有該字元串,那麼就是那段script是頁面相關信息。我們可以通過正則表達式把該script提取出來,然後把其中的html也提取出來,再保存到本地,看看信息是否全面。這里我就不截圖了。感覺還有很多要寫的,不然篇幅太長了。
另外,對於具體頁面的解析,我也不做太多的介紹了。太細的東西還是建議讀讀源碼。我只講一下,我覺得的一種處理異常的比較優雅的方式。微博爬蟲的話,主要是頁面樣式太多,如果你打算包含所有不同的用戶的模版,那麼我覺得幾乎不可能,不同用戶模版,用到的解析規則就不一樣。那麼出現解析異常如何處理?尤其是你沒有catch到的異常。很可能因為這個問題,程序就崩掉。其實對於Python這門語言來說,我們可以通過裝飾器來捕捉我們沒有考慮到的異常,比如我這個裝飾器
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def parse_decorator(return_type):
"""
:param return_type: 用於捕捉頁面解析的異常, 0表示返回數字0, 1表示返回空字元串, 2表示返回[],3表示返回False, 4表示返回{}, 5返回None
:return: 0,'',[],False,{},None
"""
def page_parse(func):
@wraps(func)
def handle_error(*keys):
try:
return func(*keys)
except Exception as e:
parser.error(e)
if return_type == 5:
return None
elif return_type == 4:
return {}
elif return_type == 3:
return False
elif return_type == 2:
return []
elif return_type == 1:
return ''
else:
return 0
return handle_error
return page_parse
上面的代碼就是處理解析頁面發生異常的情況,我們只能在數據的准確性、全面性和程序的健壯性之間做一些取捨。用裝飾器的話,程序中不用寫太多的try語句,代碼重復率也會減少很多。
頁面的解析由於篇幅所限,我就講到這里了。沒有涉及太具體的解析,其中一個還有一個比較難的點,就是數據的全面性,讀者可以去多觀察幾個微博用戶的個人信息,就會發現有的個人信息,有的用戶有填寫,有的並沒有。解析的時候要考慮完的話,建議從自己的微博的個人信息入手,看到底有哪些可以填。這樣可以保證幾乎不會漏掉一些重要的信息。
最後,我再切合本文的標題,講如何搭建一個分布式的微博爬蟲。開發過程中,我們可以先就做單機單線程的爬蟲,然後再改成使用celery的方式。這里這樣做是為了方便開發和測試,因為你單機搭起來並且跑得通了,那麼分布式的話,就很容易改了,因為celery的API使用本來就很簡潔。
我們抓取的是用戶信息和他的關注和粉絲uid。用戶信息的話,我們一個請求大概能抓取一個用戶的信息,而粉絲和關注我們一個請求可以抓取18個左右(因為這個抓的是列表),顯然可以發現用戶信息應該多佔一些請求的資源。這時候就該介紹理論篇沒有介紹的關於celery的一個高級特性了,它叫做任務路由。直白點說,它可以規定哪個分布式節點能做哪些任務,不能做哪些任務。它的存在可以讓資源分配更加合理,分布式微博爬蟲項目初期,就沒有使用任務路由,然後抓了十多萬條關注和分析,結果發現用戶信息抓幾萬條,這就是資源分配得不合理。那麼如何進行任務路由呢?
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# coding:utf-8
import os
from datetime import timedelta
from celery import Celery
from kombu import Exchange, Queue
from config.conf import get_broker_or_backend
from celery import platforms
# 允許celery以root身份啟動
platforms.C_FORCE_ROOT = True
worker_log_path = os.path.join(os.path.dirname(os.path.dirname(__file__))+'/logs', 'celery.log')
beat_log_path = os.path.join(os.path.dirname(os.path.dirname(__file__))+'/logs', 'beat.log')
tasks = ['tasks.login', 'tasks.user']
# include的作用就是注冊服務化函數
app = Celery('weibo_task', include=tasks, broker=get_broker_or_backend(1), backend=get_broker_or_backend(2))
app.conf.update(
CELERY_TIMEZONE='Asia/Shanghai',
CELERY_ENABLE_UTC=True,
CELERYD_LOG_FILE=worker_log_path,
CELERYBEAT_LOG_FILE=beat_log_path,
CELERY_ACCEPT_CONTENT=['json'],
CELERY_TASK_SERIALIZER='json',
CELERY_RESULT_SERIALIZER='json',
CELERY_QUEUES=(
Queue('login_queue', exchange=Exchange('login', type='direct'), routing_key='for_login'),
Queue('user_crawler', exchange=Exchange('user_info', type='direct'), routing_key='for_user_info'),
Queue('fans_followers', exchange=Exchange('fans_followers', type='direct'), routing_key='for_fans_followers'),
)
上述代碼我指定了有login_queue、user_crawler、fans_followers三個任務隊列。它們分別的作用是登錄、用戶信息抓取、粉絲和關注抓取。現在假設我有三台爬蟲伺服器A、B和C。我想讓我所有的賬號登錄任務分散到三台伺服器、讓用戶抓取在A和B上執行,讓粉絲和關注抓取在C上執行,那麼啟動A、B、C三個伺服器的celery worker的命令就分別是
Python
1
2
3
celery -A tasks.workers -Q login_queue,user_crawler worker -l info -c 1 # A伺服器和B伺服器啟動worker的命令,它們只會執行登錄和用戶信息抓取任務
celery -A tasks.workers -Q login_queue,fans_followers worker -l info -c 1 # C伺服器啟動worker的命令,它只會執行登錄、粉絲和關注抓取任務
然後我們通過命令行或者代碼(如下)就能發送所有任務給各個節點執行了
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
4
『玖』 如何用Python爬蟲抓取網頁內容
首先,你要安裝requests和BeautifulSoup4,然後執行如下代碼.
importrequests
frombs4importBeautifulSoup
iurl='http://news.sina.com.cn/c/nd/2017-08-03/doc-ifyitapp0128744.shtml'
res=requests.get(iurl)
res.encoding='utf-8'
#print(len(res.text))
soup=BeautifulSoup(res.text,'html.parser')
#標題
H1=soup.select('#artibodyTitle')[0].text
#來源
time_source=soup.select('.time-source')[0].text
#來源
origin=soup.select('#artibodyp')[0].text.strip()
#原標題
oriTitle=soup.select('#artibodyp')[1].text.strip()
#內容
raw_content=soup.select('#artibodyp')[2:19]
content=[]
forparagraphinraw_content:
content.append(paragraph.text.strip())
'@'.join(content)
#責任編輯
ae=soup.select('.article-editor')[0].text
這樣就可以了