python解析網頁,無出BeautifulSoup左右,此是序言
安裝
BeautifulSoup4以后的安裝需要用eazy_install,如果不需要最新的功能,安裝版本3就夠了,千萬別以為老版本就怎么怎么不好,想當初也是千萬人在用的啊。安裝很簡單
$ wget " http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.2.1.tar.gz"?
$ tar zxvf BeautifulSoup-3.2.1.tar.gz?
然后把里面的BeautifulSoup.py這個文件放到你python安裝目錄下的site-packages目錄下
site-packages是存放Python第三方包的地方,至于這個目錄在什么地方呢,每個系統不一樣,可以用下面的方式找一下,基本上都能找到
$ sudo find / -name "site-packages" -maxdepth 5 -type d?
$ find ~ -name "site-packages" -maxdepth 5?
當然如果沒有root權限就查找當前用戶的根目錄
$ find ~ -name "site-packages" -maxdepth 5 -type d?
如果你用的是Mac,哈哈,你有福了,我可以直接告訴你,Mac的這個目錄在/Library/Python/下,這個下面可能會有多個版本的目錄,沒關系,放在最新的一個版本下的site-packages就行了。使用之前先import一下
from BeautifulSoup import BeautifulSoup?
使用
在使用之前我們先來看一個實例
現在給你這樣一個頁面
http://movie.douban.com/tag/%E5%96%9C%E5%89%A7
它是豆瓣電影分類下的喜劇電影,如果讓你找出里面評分最高的100部,該怎么做呢
好了,我先曬一下我做的,鑒于本人在CSS方面處于小白階段以及天生沒有美術細菌,界面做的也就將就能看下,別吐
接下來我們開始學習BeautifulSoup的一些基本方法,做出上面那個頁面就易如反掌了
鑒于豆瓣那個頁面比較復雜,我們先以一個簡單樣例來舉例,假設我們處理如下的網頁代碼
?
?
???
?
??? This is paragraph?
???????
?
??????? one?
???????
?
??????? .?
???
???
?
??? This is paragraph?
???????
?
??????? two?
???????
?
??????? .?
???
?
?
你沒看錯,這就是官方文檔里的一個樣例,如果你有耐心,看官方文檔就足夠了,后面的你都不用看
http://www.leeon.me/upload/other/beautifulsoup-documentation-zh.html
初始化
首先將上面的HTML代碼賦給一個變量html如下,為了方便大家復制這里貼的是不帶回車的,上面帶回車的代碼可以讓大家看清楚HTML結構
html = '
This is paragraph one .
This is paragraph two .
'?初始化如下:
soup = BeautifulSoup(html)?
我們知道HTML代碼可以看成一棵樹,這個操作等于是把HTML代碼解析成一種樹型的數據結構并存儲在soup中,注意這個數據結構的根節點不是,而是soup,其中html標簽是soup的唯一子節點,不信你試試下面的操作
print soup?
print soup.contents[0]?
print soup.contents[1]?
前兩個輸出結果是一致的,就是整個html文檔,第三條輸出報錯IndexError: list index out of range
查找節點
查找節點有兩種反回形式,一種是返回單個節點,一種是返回節點list,對應的查找函數分別為find和findAll
單個節點
1.根據節點名
## 查找head節點?
print soup.find('head') ## 輸出為
## or?
## head = soup.head?
這種方式查找到的是待查找節點最近的節點,比如這里待查找節點是soup,這里找到的是離soup最近的一個head(如果有多個的話)
2.根據屬性
## 查找id屬性為firstpara的節點?
print soup.find(attrs={'id':'firstpara'})???
## 輸出為
This is paragraph one .
?## 也可節點名和屬性進行組合?
print soup.find('p', attrs={'id':'firstpara'})? ## 輸出同上
3.根據節點關系
節點關系無非就是兄弟節點,父子節點這樣的
p1 = soup.find(attrs={'id':'firstpara'}) ## 得到第一個p節點?
print p1.nextSibling ## 下一個兄弟節點?
## 輸出
This is paragraph two .
?p2 = soup.find(attrs={'id':'secondpara'}) ## 得到第二個p節點?
print p2.previousSibling ## 上一個兄弟節點?
## 輸出
This is paragraph one .
?print p2.parent ## 父節點,輸出太長這里省略部分 ...?
print p2.contents[0] ## 第一個子節點,輸出u'This is paragraph'
多個節點
將上面介紹的find改為findAll即可返回查找到的節點列表,所需參數都是一致的
1.根據節點名
## 查找所有p節點?
soup.findAll('p')
2.根據屬性查找
## 查找id=firstpara的所有節點?
soup.findAll(attrs={'id':'firstpara'})?
需要注意的是,雖然在這個例子中只找到一個節點,但返回的仍是一個列表對象
上面的這些基本查找功能已經可以應付大多數情況,如果需要各個高級的查找,比如正則式,可以去看官方文檔
獲取文本
getText方法可以獲取節點下的所有文本,其中可以傳遞一個字符參數,用來分割每個各節點之間的文本
## 獲取head節點下的文本?
soup.head.getText()???????? ## u'Page title'?
## or?
soup.head.text?
## 獲取body下的所有文本并以\n分割?
soup.body.getText('\n')???? ## u'This is paragraph\none\n.\nThis is paragraph\ntwo\n.'?
實戰
有了這些功能,文章開頭給出的那個Demo就好做了,我們再來回顧下豆瓣的這個頁面
http://movie.douban.com/tag/%E5%96%9C%E5%89%A7
如果要得到評分前100的所有電影,對這個頁面需要提取兩個信息:1、翻頁鏈接;2、每部電影的信息(外鏈,圖片,評分、簡介、標題等)
當我們提取到所有電影的信息后再按評分進行排序,選出最高的即可,這里貼出翻頁提取和電影信息提取的代碼
## filename: Grab.py?
from BeautifulSoup import BeautifulSoup, Tag?
import urllib2?
import re?
from Log import LOG?
?
def LOG(*argv):?
??? sys.stderr.write(*argv)?
??? sys.stderr.write('\n')?
?
class Grab():?
??? url = ''?
??? soup = None?
??? def GetPage(self, url):?
??????? if url.find('http://',0,7) != 0:?
??????????? url = 'http://' + url?
??????? self.url = url?
??????? LOG('input url is: %s' % self.url)?
??????? req = urllib2.Request(url, headers={'User-Agent' : "Magic Browser"})?
??????? try:?
??????????? page = urllib2.urlopen(req)?
??????? except:?
??????????? return?
??????? return page.read()???
?
??? def ExtractInfo(self,buf):?
??????? if not self.soup:?
??????????? try:?
??????????????? self.soup = BeautifulSoup(buf)?
??????????? except:?
??????????????? LOG('soup failed in ExtractInfo :%s' % self.url)?
??????????? return?
??????? try:?
??????????? items = self.soup.findAll(attrs={'class':'item'})?
??????? except:?
??????????? LOG('failed on find items:%s' % self.url)?
??????????? return?
??????? links = []?
??????? objs = []??
??????? titles = []?
??????? scores = []?
??????? comments = []?
??????? intros = []?
??????? for item in items:?
??????????? try:?
??????????????? pic = item.find(attrs={'class':'nbg'})?
??????????????? link = pic['href']?
??????????????? obj = pic.img['src']?
??????????????? info = item.find(attrs={'class':'pl2'})?
??????????????? title = re.sub('[ \t]+',' ',info.a.getText().replace(' ','').replace('\n',''))?
??????????????? star = info.find(attrs={'class':'star clearfix'})?
??????????????? score = star.find(attrs={'class':'rating_nums'}).getText().replace(' ','')?
??????????????? comment = star.find(attrs={'class':'pl'}).getText().replace(' ','')?
??????????????? intro = info.find(attrs={'class':'pl'}).getText().replace(' ','')?
??????????? except Exception,e:?
??????????????? LOG('process error in ExtractInfo: %s' % self.url)?
??????????????? continue?
??????????? links.append(link)?
??????????? objs.append(obj)?
??????????? titles.append(title)?????
??????????? scores.append(score)?
??????????? comments.append(comment)?
??????????? intros.append(intro)?
??????? return(links, objs, titles, scores, comments, intros)?
?
??? def ExtractPageTurning(self,buf):?
??????? links = set([])?
??????? if not self.soup:?
??????????? try:?
??????????????? self.soup = BeautifulSoup(buf)?
??????????? except:?
??????????????? LOG('soup failed in ExtractPageTurning:%s' % self.url)?
??????????????? return?
??????? try:?
??????????? pageturning = self.soup.find(attrs={'class':'paginator'})?
??????????? a_nodes = pageturning.findAll('a')?
??????????? for a_node in a_nodes:?
??????????????? href = a_node['href']?
??????????????? if href.find('http://',0,7) == -1:?
??????????????????? href = self.url.split('?')[0] + href?
??????????????? links.add(href)?
??????? except:?
??????????? LOG('get pageturning failed in ExtractPageTurning:%s' % self.url)?
?
??????? return links?
?
??? def Destroy(self):?
??????? del self.soup?
??????? self.soup = None?
接著我們再來寫個測試樣例
## filename: test.py?
#encoding: utf-8?
from Grab import Grab?
import sys?
reload(sys)?
sys.setdefaultencoding('utf-8')?
?
grab = Grab()?
buf = grab.GetPage('http://movie.douban.com/tag/喜劇?start=160&type=T')?
if not buf:?
??????? print 'GetPage failed!'?
??????? sys.exit()?
links, objs, titles, scores, comments, intros = grab.ExtractInfo(buf)?
for link, obj, title, score, comment, intro in zip(links, objs, titles, scores, comments, intros):?
??????? print link+'\t'+obj+'\t'+title+'\t'+score+'\t'+comment+'\t'+intro?
pageturning = grab.ExtractPageTurning(buf)?
for link in pageturning:?
??????? print link?
grab.Destroy()?
OK,完成這一步接下來的事兒就自個看著辦吧
本文只是介紹了BeautifulSoup的皮毛而已,目的是為了讓大家快速學會一些基本要領,想當初我要用什么功能都是去BeautifulSoup的源代碼里一個函數一個函數看然后才會的,一把辛酸淚啊,所以希望后來者能夠通過更便捷的方式去掌握一些基本功能,也不枉我一字一句敲出這篇文章,尤其是這些代碼的排版,真是傷透了腦筋
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
