python解析網頁中javascript動態添加的內容(一)


最近,想從中國天氣網上抓取數據,其中的網頁上的實時天氣是使用javascript生成的,用簡單的標簽解析不到。原因是,那個標簽壓根就沒再網頁當中。

所以,google了下python怎么區解析動態網頁,下面文章對我很有幫助。

轉載記錄:Python在Web Page抓取、JS解析方面的介紹

因為我只希望在mac下解析,所以我並沒有使用擴平台的庫。在使用spidermonkey后,發現它還是很全面,比如document.write就無法執行(如果我的認識有錯誤,請指出,謝謝)。我將目光落在了pywebkitgtk上,可惜安裝不成功,逼迫我放棄了(我有考慮過使用pyv8,但是還是放棄了)。

在經歷了失敗后,我還是從homebrew這個神器上發現了希望。它可以幫你安裝pyqt,可能知道它是一個python的界面庫,但是它同樣擁有網絡模塊(webkit),當然也可以使用它來解析網頁。

我將分析一下我解析動態網頁的過程,此過程實現多於原理學習:

第一步:解析靜態網頁標簽

 1 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 2 <html>
 3 <head>
 4 <title>javascript測試網頁</title>
 5 </head>
 6 <body>    
 7 <script type="text/javascript" src="./5757.js">
 8 </script>
 9 </body>
10 </html>

上面是測試用的html代碼,我將解析它的title標簽,很簡單,呵呵~

 1 #! /usr/bin/env python
 2 
 3 from htmlentitydefs import entitydefs
 4 from HTMLParser import HTMLParser
 5 import sys,urllib2
 6 
 7 class DataParser(HTMLParser):
 8               def __init__(self):
 9                             self.title = None
10                             self.isTag = 0
11                             HTMLParser.__init__(self)
12 
13               def handle_starttag(self,tag,attrs):
14                             if tag == 'title':
15                                           self.isTag = 1
16 
17 
18               def handle_data(self,data):
19                             if self.isTag:
20                                           self.title = data
21 
22               def handle_endtag(self,tag):
23                             if tag == 'title':
24                                           self.isTag = 0
25               def getTitle(self):
26                             return self.title
27 
28 url = 'file:///Users/myName/Desktop/pyqt/2.html'
29 #''中內容用瀏覽器打開,直接復制地址欄的內容即可
30 req = urllib2.Request(url)
31 fd = urllib2.urlopen(req)
32 parser = DataParser()
33 parser.feed(fd.read())
34 print "Title is:",parser.getTitle()

結果是:

第二步 安裝庫

1.我假設你已經安裝了python。

2.在開始解析動態網頁之前,先要安裝pyqt,讓brew去替你安裝,能幫你節省很多精力。。。

了解更多homebrew,請訪問官網:homebrew官網

3.說明:本來pyqt是一個GUI庫,但它包含了網絡模塊webkit,這個將用於解析動態網頁。

第三步 解析javascript動態標簽

1.有很多標簽是動態添加到html網頁中的,所以有時候用python去執行javascript可能不能達到條件,比如動態添加的標簽,所以獲得執行后dom樹是一種比較通用的方法。(可能理解不正確,如果不對,請指正)。

2.來寫一個給上面html文件外部調用的js文件。

1 alert("這是被調用的語句。")
2 var o = document.body;
3 function createDIV(text)
4 {
5     var div = document.createElement("div");
6     div.innerHTML = text;
7     o.appendChild(div);
8 }
9 createDIV("15");

3.此時,雙擊2.html,看到的效果是:

只有一個15,這就是我們要解析的數據,現在再來看下瀏覽器顯示的源碼:

是不是沒有div標簽,所以現在解析,不可能獲取到的,應為div是5757.js添加上去的(js名字亂取的)~

下面就開始解析,我的問題解決受益於這篇文章,希望大家也能看看:Scraping JavaScript webpages with webkit

我們要利用webkit獲取執行后的dom樹:

 1 #! /usr/bin/env python
 2 
 3 import sys,urllib2
 4 from HTMLParser import HTMLParser
 5 from PyQt4.QtCore import *
 6 from PyQt4.QtGui import *
 7 from PyQt4.QtWebKit import *
 8 
 9 class Render(QWebPage):  
10   def __init__(self, url):  
11     self.app = QApplication(sys.argv)  
12     QWebPage.__init__(self)  
13     self.loadFinished.connect(self._loadFinished)  
14     self.mainFrame().load(QUrl(url))  
15     self.app.exec_()  
16   
17   def _loadFinished(self, result):  
18     self.frame = self.mainFrame()  
19     self.app.quit()  
20   
21 url = './2.html'  
22 r = Render(url)  
23 html = r.frame.toHtml()
24 print html.toUtf8()
25 
26 # 將執行后的代碼寫入文件中
27 f = open('./test.txt','w')
28 f.write(html.toUtf8())
29 f.close()

我顯示print出來結果,后又將結果寫入test.txt文件。現在來看看test.txt中有什么(不要雙擊,否則只有一個15,用你的文本編輯器去查看,比如:sublime text2):

 1 <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 2 
 3 
 4 <title>javascript測試網頁</title>
 5 </head>
 6 <body>    
 7 <script type="text/javascript" src="./5757.js">
 8 </script><div>15</div>
 9 
10 </body></html>

看起來像html代碼,但是得到了我想要的東西,注意第八行,出現了div標簽~。

最后一步,獲取那個15。

停一下,想一下我們怎么去獲取:

1 html = r.frame.toHtml()

得到一個QString對象,它不屬於python標准庫。我想在我熟悉pyqt的始末之前,將它轉換成python對象讓我感到更加自在一點。我們可以像解析靜態網頁般區解析它,關鍵在於這一句: 

1 parser.feed(fd.read())

當然既然能將它寫入到本地文件,打開文件->解析文件->獲取數據也是可以的,但我想沒人想那么麻煩。

查閱一下python的文檔:

1 HTMLParser.feed(data)
2 
3 Feed some text to the parser. It is processed insofar as it consists of complete elements; incomplete data is buffered until more data is fed or close() is called.data can be either unicode or str, but passing unicode is advised.

發現只要將unicode或str傳入,我們就能順利解析,也許稍微改動下代碼即可:

 1 ! /usr/bin/env python
 2 
 3 
 4 import sys,urllib2
 5 from HTMLParser import HTMLParser
 6 from PyQt4.QtCore import *
 7 from PyQt4.QtGui import *
 8 from PyQt4.QtWebKit import *
 9 
10 class DataParser(HTMLParser):
11               def __init__(self):
12                             self.div = None
13                             self.isTag = 0
14                             HTMLParser.__init__(self)
15 
16               def handle_starttag(self,tag,attrs):
17                             if tag == 'div':
18                                           self.isTag = 1
19 
20 
21               def handle_data(self,data):
22                             if self.isTag:
23                                           self.title = data
24 
25               def handle_endtag(self,tag):
26                             if tag == 'div':
27                                           self.isTag = 0
28               def getDiv(self):
29                             return self.title
30 
31 
32 class Render(QWebPage):  
33   def __init__(self, url):  
34     self.app = QApplication(sys.argv)  
35     QWebPage.__init__(self)  
36     self.loadFinished.connect(self._loadFinished)  
37     self.mainFrame().load(QUrl(url))  
38     self.app.exec_()  
39   
40   def _loadFinished(self, result):  
41     self.frame = self.mainFrame()  
42     self.app.quit()  
43   
44 url = './2.html'  
45 r = Render(url)  
46 html = r.frame.toHtml()
47 #print html.toUtf8()
48 
49 parser = DataParser()
50 parser.feed(str(html.toUtf8()))
51 print "javascript is",parser.getDiv()
52 
53 
54 #f = open('./test.txt','w')
55 #f.write(html.toUtf8())
56 #f.close()

代碼做了簡單的合並,就將數據解析出來了,運行結果如下:

呵呵,雖然只有3個詞,但的確成功解析了動態標簽,呵呵~

第四步 想說的話

文章的實現多於原理,希望對閱讀文章的人提供一定的幫助。如有不對的地方也請指正。

當然,要將文章的東西直接運用到實際是不現實的,但希望這是一個好的起點。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM