本文在學習慕課網 瘋狂的螞蟻crazyant 的課程後寫做,文中截圖部分來自於視頻,感謝視頻做者。你們也能夠經過點擊這裏觀看視頻學習,老師講得賊棒!html
通俗的講,爬蟲就是經過一個URL開始,自動獲取數據的「網絡機器人」。node
存儲未爬取的URL和爬取過的URLpython
將互聯網上URL對應的網頁下載到本地的工具,本文介紹Python自帶庫「urllib2」正則表達式
最簡單的使用方法sql
添加data、http header數據庫
添加特殊情景的處理器(HTTPCookieProcessor、ProxyHandler、HTTPSHandler、HTTPRedirectHandler)服務器
以添加HTTPCookieProcessor爲例:網絡
網頁解析器是從網頁中提取有價值數據的工具。架構
其中,正則表達式是基於文本的模糊匹配;其餘3種方式將網頁文檔解析爲DOM樹解析。app
官網:https://www.crummy.com/software/BeautifulSoup/
find_all
會搜索全部知足要求的節點,find
搜索出知足要求的第一個節點。建立Beautiful Soup對象
搜索節點(find_all,find)
訪問節點信息
肯定目標
也就是說:咱們須要扒取哪一個網站和哪些數據。
本實例咱們肯定要抓取百度百科「python」詞條這個頁面和它相關的頁面,數據包括頁面內的關鍵詞、簡介。
分析目標
本實例抓取的URL是頁面中的其餘詞條的超連接,格式相似於<a href="/item/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80">計算機程序設計語言</a>
本實例都是字符串格式的數據
百度百科網頁使用utf-8
編碼,因此在編寫代碼中注意轉碼
執行爬蟲
主模塊
# -*- coding:utf-8 -*- import url_manager import html_downloader import html_parser import html_outputer class SpiderMain(object): def __init__(self): self.urls = url_manager.UrlManager() # 初始化URL管理器 self.downloader = html_downloader.HtmlDownloader() # 初始化網頁下載器 self.parser = html_parser.HtmlParser() # 初始化網頁解析器 self.outputer = html_outputer.HtmlOutputer() # 初始化數據輸出器 def craw(self,root_url): count = 1 # 記錄成功條數 self.urls.add_new_url(root_url) # 添加url到url管理器 while self.urls.has_new_url(): try: new_url = self.urls.get_new_url() # 獲取未爬過的url print 'craw %d : %s' %(count, new_url) html_cont = self.downloader.download(new_url) # 根據url下載網頁 new_urls, new_data = self.parser.parse(new_url, html_cont) # 解析網頁內容 self.urls.add_new_urls(new_urls) # 將爬到的新網址添加到url管理器 self.outputer.collect_data(new_data) # 將內容添加到數據輸出器 if count == 1000: break count = count + 1 except: print 'craw failed' self.outputer.output_html() # 輸出內容 # main函數 if __name__ == '__main__': root_url = 'https://baike.baidu.com/item/Python' # 最開始的url obj_spider = SpiderMain() obj_spider.craw(root_url)
URL管理器
# -*- coding:utf-8 -*- # URL管理器 class UrlManager(object): def __init__(self): self.new_urls = set() # 存放未讀取url self.old_urls = set() # 存放已讀取url # 添加一個url到未讀url列表 def add_new_url(self, url): if url is None: return if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) # 添加多個url到未讀url列表 def add_new_urls(self, urls): if urls is None or len(urls) == 0: return for url in urls: self.add_new_url(url) # 返回是否有未讀url def has_new_url(self): return len(self.new_urls) != 0 # 隨機獲取一個未讀url def get_new_url(self): new_url = self.new_urls.pop() # 獲取未讀url並刪除 self.old_urls.add(new_url) # 添加這個url到已讀url列表中 return new_url
網頁下載器
# -*- coding:utf-8 -*- import urllib2 # 網頁下載器 class HtmlDownloader(object): # 獲取服務器響應內容 def download(self,url): if url is None: return None response = urllib2.urlopen(url) if response.getcode() != 200: # 獲取成功標識 return None return response.read()
網頁解析器
# -*- coding:utf-8 -*- from bs4 import BeautifulSoup import re # 網頁解析器 class HtmlParser(object): # 獲取其中的url def __get_new_urls(self,page_url, soup): new_urls = set() links = soup.find_all('a', href=re.compile(r'/item/[a-zA-Z0-9%]+')) # 匹配url,可能會發生變化 for link in links: new_url = link['href'].encode('utf-8') # 獲取url new_full_url = 'https://baike.baidu.com'+new_url # 拼接url new_urls.add(new_full_url) return new_urls # 獲取其中的內容(關鍵詞,簡介) def __get_new_data(self,page_url,soup): res_data = {} res_data['url'] = page_url # 獲取關鍵詞 title_node = soup.find('dd', class_ = 'lemmaWgt-lemmaTitle-title').find('h1') res_data['title'] = title_node.get_text() # 獲取簡介 summary_node = soup.find('div', class_ = 'lemma-summary') res_data['summary'] = summary_node.get_text() return res_data # 解析htnl字符串 def parse(self,page_url,html_cont): if page_url is None or html_cont is None: return soup = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8') new_urls = self.__get_new_urls(page_url, soup) new_data = self.__get_new_data(page_url, soup) return new_urls, new_data
數據輸出器
# -*- coding:utf-8 -*- # 數據輸出器 class HtmlOutputer(object): def __init__(self): self.datas = list() # 添加數據到列表中 def collect_data(self, data): if data is None: return self.datas.append(data) # 輸出到html文件中 def output_html(self): fout = open(r'output.html','w') fout.write('<html>') fout.write('<body>') fout.write('<table>') for data in self.datas: fout.write('<tr>') fout.write('<td>%s</td>' % data['url']) fout.write('<td>%s</td>' % data['title'].encode('utf-8')) fout.write('<td>%s</td>' % data['summary'].encode('utf-8')) fout.write('</tr>') fout.write('</table>') fout.write('</body>') fout.write('</html>') fout.close()