BeautifulSoup與正則_簡單爬蟲python3實現

Pop_Rain發表於2017-06-12

本文的內容python3自我實現程式碼見最下方的程式碼

============以下轉載自:http://blog.csdn.net/w93223010/article/details/20358683===============

本節的內容主要是如何使用一個Python 寫的一個 HTML/XML的解析器——BeautifulSoup,用它將上一節生成的result檔案(就是抓取儲存的網頁原始碼)中所需的內容取出。關於BeautifulSoup的簡介和下載安裝請參考黃聰仁兄的部落格。另附BeautifulSoup中文文件

先上程式碼:

[python] view plain copy
  1. from bs4 import BeautifulSoup  
  2.   
  3. txt='D:\\result1.html'  
  4. f = open(txt, "r")  
  5. html=f.read()  
  6. f.close()  
  7.   
  8. bs=BeautifulSoup(html)  
  9. gvtitle=bs.find_all('div',attrs={'class':'gvtitle'})  
  10. for title in gvtitle:  
  11.     print title.a.text  

1行在程式中引入了BeautifulSoup

36行是檔案操作,將result1.html檔案中的內容讀取到html變數中。

89行使用BeautifulSouphtml變數進行格式化,並使用find_all方法獲取到所需的資料物件。

1011行將獲取的“產品名稱”資訊全部展示出來。

對上段的程式碼進一步解釋:

首先,第一個需求是獲取如圖2-1所示的產品的產品名稱資訊,即“NewFashion Men Slim Fit Cotton V-Neck Short Sleeve Casual T-Shirt Tops”。


2-1


其次,觀察result1.html中的原始碼發現,與48個產品相對應,產品名稱全部放在classgvtitle48div內,如圖2-2所示。因此使用find_all方法查詢出所有含class屬性值為gvtitlediv,以列表的形式存入gvtitle變數中。


2-2


之後,進一步觀察圖2-2html檔案的結構,發現“New Fashion Men Slim Fit Cotton V-Neck Short Sleeve Casual T-ShirtTops”這行文字就放在div標籤內的a標籤中,所以在程式碼的第10行用.a.text獲取並展示。上段程式執行結果如圖2-3


2-3


接下來修改程式碼,進一步獲取產品的價格資訊。這部分使用了正規表示式,關於正規表示式的知識請參考——正規表示式入門教程

程式碼如下:

[python] view plain copy
  1. import re     
  2. from bs4 import BeautifulSoup  
  3.   
  4. def getItems(html):  
  5.     pattern = re.compile('\d+.\d+')  
  6.         items = re.findall(pattern,html)  
  7.     return items  
  8.   
  9. txt='D:\\result1.html'  
  10. f = open(txt, "r")  
  11. html=f.read()  
  12. f.close()  
  13.   
  14. bs=BeautifulSoup(html)  
  15. gvtitle=bs.find_all('div',attrs={'class':'gvtitle'})  
  16. for title in gvtitle:  
  17.     print title.a.text  
  18.       
  19. prices=bs.find_all('span',attrs={'class':'amt'})  
  20. for pri in prices:  
  21.     result=getItems(str(pri))  
  22.     print result  


1行引入正規表示式

47行定義了一個方法,功能是使用正規表示式對BeautifulSoup獲取來的資料進一步篩選。

19行使用find_all方法獲取到所需的價格。不過觀察result1.html中的原始碼發現,classamtspan中的資料不如第15行獲取的資料那麼規則,所以在第21行呼叫了getItems方法對資料進一步篩選,獲得價格。

 

程式執行結果如圖2-4,不過有些產品獲取到了2個價格。這是因為有些產品下有多個子產品,這兩個數值表示的是最低價和最高價,如圖2-5

為求結果集簡單,就將兩值取平均值作為最終值。


圖2-4


圖2-5


修改程式碼,最後如下:

[python] view plain copy
  1. import re  
  2. import sys  
  3. from bs4 import BeautifulSoup  
  4.   
  5. def getItems(html):  
  6.     pattern = re.compile('\d+.\d+')  
  7.         items = re.findall(pattern,html)  
  8.     return items  
  9.       
  10. p=0  
  11. while p<5:  
  12.     print ' =='+str(p+1)+'==start=='  
  13.     txt='D:\\result'+str(p+1)+'.html'  
  14.     fr = open(txt, "r")  
  15.     html=fr.read()  
  16.     bs=BeautifulSoup(html)  
  17.     gvtitle=bs.find_all('div',attrs={'class':'gvtitle'})   
  18.       
  19.     pri_list=[]  
  20.     prices=bs.find_all('span',attrs={'class':'amt'})      
  21.     for pri in prices:  
  22.         res=getItems(str(pri))  
  23.         if len(res)==2:  
  24.             val=(float(res[0])+float(res[1]))/2  
  25.             pri_list.append(val)  
  26.         else:  
  27.             pri_list.append(res[0])  
  28.       
  29.     j=0  
  30.     while j<48:  
  31.         try:  
  32.             print gvtitle[j].a.text,pri_list[j]  
  33.         except UnicodeEncodeError, e:             
  34.             for s in gvtitle[j].a.text:  
  35.                 try:  
  36.                     sys.stdout.write(s)  
  37.                 except UnicodeEncodeError, e:  
  38.                     continue  
  39.             sys.stdout.flush()  
  40.             print pri_list[j]                         
  41.         j=j+1  
  42.     print ' =='+str(p+1)+'====end=='  
  43.     p=p+1  
  44. fr.close()  

3140行古怪的輸出程式碼是為了刪除掉產品名稱中有時會出現的“™”符號,暫時沒想到更好的辦法,懇請各位童鞋指教。

===============================以下是python3的實現程式碼==================================

#下載網頁原始碼並寫入檔案
import urllib.request

url = "http://www.ebay.com/sch/TShirts-/15687/i.html?Style=Basic%2520Tee&_dcat=15687&Color=Black&_pgn=1"
req = urllib.request.Request(url)
html_open = urllib.request.urlopen(req)
html_data = html_open.read()
html = str(html_data.decode("utf8"))  #先read再decode

html = html.replace("\xa0"," ")
html = html.replace("\xa9"," ")
html.encode("gbk") #寫入txt中儘量用gbk編碼

file_name = "f:/test/1.txt"
file_open = open(file_name, "a") #將網頁原始碼寫入1.txt中
file_open.write(html)
file_open.close()
#用bs解析頁面並提取資料資訊_商品名稱
from bs4 import BeautifulSoup
pagepath = "f:/test/pagecode.txt"
pagedata = open(pagepath)
html = pagedata.read()
pagedata.close()

bs = BeautifulSoup(html,"lxml")
gvtitle = bs.find_all("div", attrs={"class":"gvtitle"}) #返回列表形式gvtitle
for title in gvtitle:
    print(title.a.text)
#用bs解析頁面並提取資料資訊_商品價格
from bs4 import BeautifulSoup
pagepath = "f:/test/pagecode.txt"
pagedata = open(pagepath)
html = pagedata.read()
pagedata.close()

bs = BeautifulSoup(html,"lxml")
gvtitle = bs.find_all("div", attrs={"class":"gvprices"}) #返回列表形式gvpricesd
for title in gvtitle:
    print(title.span.text)
#以上兩端程式碼的彙總實現:用bs解析頁面並提取資料資訊_商品名稱+價格(bs+正則)
import re
from bs4 import BeautifulSoup
pagepath = "f:/test/pagecode.txt"
pagedata = open(pagepath)
html = pagedata.read()
pagedata.close()

def getItems(html):  
    pattern = re.compile("(\d+.\d*)") #正規表示式
    items = re.findall(pattern,html)
    if len(items)==2:
        ret = (float(items[0])+float(items[1]))/2  #如果價格是一個區間計算平均值
    else:
        ret = items[0]
    return ret

bs=BeautifulSoup(html, "lxml")  
gvtitle=bs.find_all('div',attrs={'class':'gvtitle'})  
for title in gvtitle:  
    print (title.a.text  )
      
prices=bs.find_all('span',attrs={'class':'amt'})  
for pri in prices:  
    result=getItems(str(pri))
    print (result)

相關文章