1、前言html
本文適合有必定Python基礎的同窗學習Python爬蟲,無基礎請點擊:慕課網——Python入門
申明:實例的主體框架來自於慕課網——Python開發簡單爬蟲node
語言:Python2python
IDE:VScode
2、何爲爬蟲正則表達式
傳統爬蟲從一個或若干初始網頁的URL開始,得到初始網頁上的URL,而後下載隊列中的URL地址對應的網頁。解析後抓取網頁內容,不斷從當前頁面上抽取新的URL放入隊列,直到知足系統的必定中止條件。同時,它還會根據必定的搜索策略獲取咱們所需的信息並保存下來。最後爲了展現咱們爬到的數據,每每還會用HTML的表格或記事本保存咱們所須要的數據。
簡單來講,爬蟲就是一門用來從互聯網上自動獲取咱們所需數據的技術。
3、JD商品詳情頁的網頁分析瀏覽器
入口URL選擇爲JD某商品詳情頁:https://item.jd.com/4224129.htmlapp
咱們須要分析的內容主要有:框架
3.1詳情頁上指向的其餘URLide
咱們打開https://item.jd.com/4224129.html,發現網頁上還有不少指向其餘商品的連接。學習
經過鼠標右鍵,查看元素,咱們能夠發現商品頁面上的以上連接均爲如下格式: //item.jd.com/數字.html測試
分析到此,咱們就知道抓取網頁內容時,從當前頁面上抽取新的URL的方法了。
3.2商品名稱、價格
同理,咱們在商品名稱和價格處點擊鼠標右鍵查看元素
4、簡單爬蟲框架
1.爬蟲總調度程序
即咱們的main文件,以入口URL爲參數爬取全部相關頁面
2.URL管理器
維護待爬取和已爬取的URL列表
3.HTML下載器
主要功能是下載指定的url,這裏用到了urllib2
4.HTML解析器
主要功能是獲取網頁上所需的URL和內容,用到BeautifulSoup
正則表達式的基礎知識能夠參見
另外安利一個網站,在寫正則表達式的時候能夠先測試,很實用
5.輸出程序
將爬取到的數據寫入HTML文件中,利用HTML的table展現
5、源碼
1.爬蟲總調度程序
import url_manager, html_downloader, html_parser, html_outputer class SpiderMain(object): def __init__(self): self.urls = url_manager.UrlManager() self.downloader = html_downloader.Html_DownloaDer() self.parser = html_parser.HtmlParser() self.outputer = html_outputer.HtmlOutputer() #爬蟲調度程序 def craw(self, root_url): count = 1 #入口URL添加進URL管理器 self.urls.add_new_url(root_url) #啓動循環,獲取待扒取的URL,而後交給下載器下載頁面,調用解析器解析頁面 while self.urls.has_new_url(): try: new_url = self.urls.get_new_url() print 'craw',count, ':' ,new_url html_cont = self.downloader.download(new_url) #獲得新的URL列表和內容 new_urls, new_data = self.parser.parse(new_url,html_cont) #新的URL存到URL管理器,同時進行數據的收集 self.urls.add_new_urls(new_urls) self.outputer.collect_data(new_data) if count == 10: break count = count +1 except: print 'craw dailed' #調用output_html展現爬取到的數據 self.outputer.output_html() if __name__ == "__main__": #入口URL root_url = "https://item.jd.com/4224129.html" obj_spider = SpiderMain() #啓動爬蟲 obj_spider.craw(root_url)
2.URL管理器
class UrlManager(object): def __init__(self): #未爬取URL列表,已爬取URL列表 self.new_urls = set() self.old_urls = set() #判斷管理器中是否有新的待扒取的URL def has_new_url(self): return len(self.new_urls) != 0 #獲取一個新的待扒取的URL def get_new_url(self): #pop方法:獲取列表中的一個URL並移除它 new_url = self.new_urls.pop() self.old_urls.add(new_url) return new_url #向管理器添加一個新的URL def add_new_url(self, url): if url is None: return #發現新的未添加的URL,則加入待扒取URL列表 if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(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)
3.HTML下載器
import urllib2 class Html_DownloaDer(): def download(self, url): if url is None: return None #調用urllib2庫的urlopen方法獲取 類文件對象(fd) response """ response = urllib2.urlopen(url)""" #調用urllib2庫的Request方法建立request對象 request = urllib2.Request(url) #添加數據 request.add_data('a') #添加htp和header(假裝成瀏覽器) request.add_header('User-Agent','Mozilla/5.0') #發送請求獲取結果 response = urllib2.urlopen(request) #獲取狀態碼,200表示成功 if response.getcode() != 200: return None return response.read()
4.HTML解析器
from bs4 import BeautifulSoup import re import urlparse class HtmlParser(object): def _get_new_urls(self, page_url, soup): new_urls = set() #獲取全部的連接 #格式如:<a target="_blank" title="華爲(HUAWEI)..." href="//item.jd.com/12943624333.html"> links = soup.find_all('a',href = re.compile(r"//item.jd.com/\d+\.htm")) #遍歷轉化爲完整的URL for link in links: new_url = link['href'] new_full_url = urlparse.urljoin(page_url,new_url) #將結果存到一個新的列表裏 new_urls.add(new_full_url) return new_urls def _new_data(self, page_url, soup): res_data = {} #URL res_data['url'] = page_url #匹配標題 #<div class="sku-name">華爲(HUAWEI) MateBook X 13英寸超輕薄微邊框筆記本(i5-7200U 4G 256G 拓展塢 2K屏 指紋 背光 office)灰</div> title_node = soup.find('div',class_ = "sku-name") res_data['title'] = title_node.get_text() #匹配價格 #<div class="dd"> #<span class="p-price"><span>¥</span><span class="price J-p-7430495">4788.00</span></span> """下載的網頁源碼無價格信息<span class="price J-p-7430495"></span></span>!!!!!""" price_node = soup.find('span',class_ = re.compile(r"price\sJ\-p\-\d+")) res_data['price'] =price_node.get_text() return res_data def parse(self, page_url, html_cont): if page_url is None or html_cont is None: return soup = BeautifulSoup(html_cont,'html.parser') new_urls = self._get_new_urls(page_url,soup) _new_data = self._new_data(page_url,soup) return new_urls, _new_data
5.輸出程序
class HtmlOutputer(object): def __init__(self): self.datas = [] def collect_data(self,data): if data is None: return self.datas.append(data) def output_html(self): fout = open('output.html','w') fout.write("<html>") fout.write("<head>") fout.write('<meta charset="UTF-8">') fout.write("<body>") fout.write("<table>") #python默認編碼是ascii,中文可能會亂碼,故加上encode('utf-8') 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['price'].encode('utf-8')) fout.write("</tr>") fout.write("</table>") fout.write("</body>") fout.write("</head>") fout.write("</html>")
6、待解決問題
關於我爬取不到價格的問題...
調試中發現我已爬取到了對應的內容,惟獨少了價格...一度扎心啊...
在 Python爬蟲——實戰一:爬取京東產品價格(逆向工程方法) - CSDN博客 上看到如下論述
可是...我查看源碼的時候真的是有價格的啊...求大神解惑
ps:第一次寫博客,思路不是很清晰,歡迎學習交流指正。