技術篇:Python爬蟲介紹

首次看本專欄文章的小伙建議先看一下介紹專欄結構的這篇文章:專欄文章分類及各類內容簡介。

爬蟲是一段自動抓取互聯網信息的程序。互聯網由各種各樣的網頁構成,每一個網頁都對應對應著url,url頁面上又有很多指向其他的頁面url,url之間相互的指向關係形成一個網狀,這就是互聯網。正常情況下,我們使用人工的方式從互聯網上獲取我們所需要的、有價值的、感興趣的東西,這種方式的特點就是覆蓋面比較小。爬蟲方法根據設定的主題和感興趣的目標可以自動的從互聯網上獲取我們所需要的數據,爬蟲從一個url出發,訪問它所關聯的所有url,並且從每一個頁面上獲取提取所需要有價值的數據。爬蟲就是自動訪問互聯網並且提取數據的程序。

該篇文章與專欄主題的關係

在機器學習、數據挖掘領域,爬蟲技術主要用於收集數據。爬蟲獲取的數據可以認為是「未經加工的數據集」,在對這些「生數據」進行處理後,便可以獲得用來直接進行訓練的「訓練集」、進行演算法性能測試的「測試集」等。所以了解爬蟲技術、學會使用爬蟲技術爬取數據也是機器學習、數據挖掘任何子領域學習者及從業者必須掌握的一項基本技能,不僅僅局限於推薦系統領域。

爬蟲技術架構

首先由爬蟲調度端來啟動、停止、監視爬蟲情況,接下來進入循環爬蟲過程。循環爬蟲的過程主要是URL管理器、頁面下載器、網頁下載器三者進行信息交互的過程。其中,URL管理器部分主要負責管理將要爬取的URL;頁面下載器主要負責將互聯網上URL對應的網頁下載到本地;網頁解析器則通過網頁解釋器解析、獲取你想要的、感興趣的內容。在後面的內容里會更加詳細地介紹這三個部分。

下圖為爬蟲的架構圖:

爬蟲過程的順序圖

爬蟲過程的時序圖可以清晰、直觀的展示整個爬蟲的過程。具體過程概述如下:首先調度端啟動爬蟲,詢問url管理器是否有要爬取的url。url管理器將要爬取的url返還給調度端,調度端根據獲取的url,利用網頁下載器下載url對應的頁面內容。網頁下載器將下載好的內容發給頁面解析器來解析,返回解析好的內容和新的url列表,獲取所感興趣的有價值的數據。根據時序圖可以直觀了解爬蟲過程,如下圖所示:

爬蟲各部分的介紹

1. 爬蟲調度器

爬蟲調度器負責啟動、停止、監視爬蟲的情況,是整個爬蟲過程的入口

2.URL管理器

URL管理器是用來管理待爬取的URL集合和已爬取的URL集合,使用URL管理器的原因是為了防止重複抓取、循環抓取:有很多網頁中可能有相同的url網址,因此如果沒有url管理器,可能會出現重複爬取某頁面的情況,降低效率;另外一種情況是爬取兩個互相關聯的頁面A、B時,爬取頁面A將獲得頁面B的url,接著爬取頁面B又獲得了頁面A的url這是就發生了循環爬取。而url管理器則可以很好地解決上述兩種情況。

那麼url管理器主要完成了哪些功能呢?首先url管理器添加了新的url到待爬取集合中,判斷了待添加的url是否在容器中、是否有待爬取的url,並且獲取待爬取的url,將url從待爬取的url集合移動到已爬取的url集合。下圖可以清晰直觀地看到url管理器完成的功能:

3. 網頁下載器

將互聯網上url對應的頁面下載到本地的工具。實現的過程如下:下載器將接收到的url傳給互聯網,互聯網返回html文件給下載器,下載器將其保存到本地。實現過程如下圖所示:

4. 頁面解析器

頁面解析器主要完成的是從獲取的html網頁字元串中取得有價值的感興趣的數據和新的url列表。實現過程如下圖所示:

使用Python語言實現爬蟲的實例代碼

下面是爬取百度百科python詞條相關的1000個頁面的數據的示常式序(完整代碼請見:本文爬蟲代碼):

1.調度端主程序(spider_main.py)

# -*- coding: UTF-8 -*-nimport url_manager,html_downloader,html_outputer,html_parsernclass SpiderMain(object):n def __init__(self):n self.urls = url_manager.UrlManager()n self.downloader = html_downloader.HtmlDownloader()n self.parser = html_parser.HtmlParser()n self.outputer = html_outputer.HtmlOutputer()n def craw(self,root_url):n self.urls.add_new_url(root_url)n count = 1n while self.urls.has_new_url():n new_url = self.urls.get_new_url()n print("craw %d:%s"%(count, new_url))n html_cont = self.downloader.downloder(new_url)n new_urls, new_data = self.parser.parser(new_url, html_cont)n self.urls.add_new_urls(new_urls)n self.outputer.collect_data(new_data)n try:n if count == 1000:n breakn count += 1n except:n print("failed")nnn self.outputer.output_html()nnif __name__ == "__main__":n root_url = "http://baike.baidu.com/item/Python"n obj_spider = SpiderMain()n obj_spider.craw(root_url)n

2.url管理器(url_manager.py)

# -*- coding: UTF-8 -*-nclass UrlManager(object):n def __init__(self):n self.new_urls = set()n self.old_urls = set()nn def add_new_url(self,url):n if url is None:n returnn if url not in self.new_urls and url not in self.old_urls:n self.new_urls.add(url)nnn def add_new_urls(self,urls):n if urls == None or len(urls) == 0:n returnn for url in urls:n self.add_new_url(url)nnn def get_new_url(self):n new_url = self.new_urls.pop()n self.old_urls.add(new_url)n return new_urlnnn def has_new_url(self):n return len(self.new_urls) !=0n

3.下載器(html_downloader.py)

# -*- coding: UTF-8 -*-nnimport urllib2nnclass HtmlDownloader(object):nn def downloder(self,url):nn if url is None:nn return Nonenn response = urllib2.urlopen(url)nn if response.getcode() != 200:nn return Nonenn return response.read()n

4.解析器(html_paser.py)

# -*- coding: UTF-8 -*-nfrom bs4 import BeautifulSoupnimport re,urlparsenclass HtmlParser(object):nn def _get_new_urls(self,page_url, soup):n new_urls = set()n links = soup.find_all(a,href=re.compile(r/item))n for link in links:n new_url = link[href]n new_full_url = urlparse.urljoin(page_url, new_url)n new_urls.add(new_full_url)n return new_urlsnn def _get_new_datas(self,page_url, soup):n new_datas = {}n #urln new_datas[url] = page_urln #<dd class="lemmaWgt-lemmaTitle-title"><h1>Python</h1>n title_node = soup.find(dd,class_=lemmaWgt-lemmaTitle-title).find(h1)n #print(title_node)n new_datas[title] = title_node.get_text()n #<div class="lemma-summary" label-module="lemmaSummary">nn summary_node = soup.find(div,class_="lemma-summary")n if summary_node is None:n returnn # print(summary_node)n new_datas[summary] = summary_node.get_text()n return new_datasnn def parser(self,page_url, html_cont):n if page_url is None or html_cont is None:n returnn soup = BeautifulSoup(html_cont, html.parser, from_encoding=utf-8)n new_urls = self._get_new_urls(page_url, soup)n new_data = self._get_new_datas(page_url, soup)n return new_urls,new_datan

5.輸出(html_outputer.py)

# -*- coding: UTF-8 -*-nclass HtmlOutputer(object):n def __init__(self):n self.datas = []n def collect_data(self,data):n if data is None or len(data) == 0:n returnn self.datas.append(data)nn def output_html(self):n fout = open(output.html,w)n fout.write("<html>")n fout.write("<body>")n fout.write("<table>")nn for data in self.datas:n fout.write("<tr>")n fout.write("<td>%s</td>"%data[url])n fout.write("<td>%s</td>" % data[title].encode(utf-8))n fout.write("<td>%s</td>" % data[summary].encode(utf-8))nn fout.write("<tr>")nn fout.write("</table>")n fout.write("</body>")n fout.write("</html>")n fout.close()n

6.爬取結果截圖:

參考資料

  1. Python開發簡單爬蟲_python爬蟲入門教程_python爬蟲視頻教程-慕課網
  2. 史上最全Python數據分析學習路徑圖 - OPEN 開發經驗庫

推薦閱讀:

左手用R右手Python系列17——CSS表達式與網頁解析
python2.7爬蟲中decode("utf-8")出錯該如何解決?
如何爬取搜索引擎下某個關鍵字對應的所有網站?
網頁上的一張圖片右鍵選擇新窗口打開是正常的,直接複製地址到地址欄打開就不正常了。誰知道是什麼原因嗎?
矽谷之路45:如何設計Crawler(二)多線程並發設計

TAG:Python | 网页爬虫 |