python抓網頁數據【ref:http://www.1point3acres.com/bbs/thread-83337-1-1.html】


前言:
數據科學越來越火了,網頁是數據很大的一個來源。最近很多人問怎么抓網頁數據,據我所知,常見的編程語言(C++,java,python)都可以實現抓網頁數據,甚至很多統計\計算的語言(R,Matlab)都有可以實現和網站交互的包。本人試過用java,python,R抓網頁,感覺語法各有差異,邏輯上是一樣的。我准備用python來大概講講抓網頁是什么概念,具體的內容要自己看手冊或者google別人的博客,這里算是拋磚引玉了。水平有限,出現錯誤或者有更好的辦法,歡迎討論。. more info on 1point3acres.com

步驟一:熟悉Python的基本語法
已經熟悉Python的直接跳到步驟二。
Python是門比較容易入門的編程語言,如何上手視編程基礎而定。
(1) 如果有一定編程的基礎,建議看google's python class,鏈接https://developers.google.com/edu/python/?hl=zh-CN&csw=1-google 1point3acres
這個是一個為期兩天的短期培訓課程(當然,是兩個全天),大概是七個視頻,每個視頻之后給編程作業,每個作業一個小時之內可以完成。這是我學習python的第二門課(第一門是codecademy的python,很早之前看的,很多內容都記不得了),當時每天看視頻+編程作業一個多小時,六天弄完,效果還不錯,用python寫基本的程序沒有問題。
(2) 如果是沒有任何編程基礎,建議看coursera上Rice University開的An Introduction to Interactive Programming in Python。這門課我沒有跟過,但是看coursetalk的評論反映非常好,地里也有同學評論(點這里),課程鏈接:https://www.coursera.org/course/interactivepython。Udacity上的CS101也是不錯的選擇,地里有相關的討論帖(點這里),而且這門課就叫做build a search engine,會專門講一些和網絡相關的module。其他學習資源還有code school和codecademy,這些資源也是挺不錯的,但是編程量太少,初學者還是系統的跟課、多練練手來打好基礎吧。
當然,每個人的偏好不同,我推薦的不一定適合你。可以先看看這個帖子【長期加分貼】介紹你上過的公開課里面其他人是怎么說的,或者上coursetalk.org看看課程評論,再決定吧。


步驟二:學會如何與網站建立鏈接,得到網頁數據。
寫腳本與網站進行交互,要熟悉python和網頁相關的幾個module(urllib,urllib2,httplib)中的一個,知道一個即可,其他的都類似的。這三個是python提供的和網頁交互的基本module,還有其他的一些,比如:mechanize和scrappy,我沒有用過,可能有更好的性能,歡迎了解的來補充。基本的網頁抓取,前面的三個module足矣。
下面的代碼演示如何用urllib2與google scholar進行交互,獲得網頁信息。

# 導入模塊 urllib2
import urllib2
# 隨便查詢一篇文章,比如On random graph。對每一個查詢google 
# scholar都有一個url,這個url形成的規則是要自己分析的。
query = 'On+random+graph'
url = 'http://scholar.google.com/scholar?hl=en&q=' + query + '&btnG=&as_sdt=1%2C5&as_sdtp='
# 設置頭文件。抓取有些的網頁不需要專門設置頭文件,但是這里如果不設置的話,. 鐗涗漢浜戦泦,涓€浜╀笁鍒嗗湴
# google會認為是機器人不允許訪問。另外訪問有些網站還有設置Cookie,這個會相對復雜一些,
# 這里暫時不提。關於怎么知道頭文件該怎么寫,一些插件可以看到你用的瀏覽器和網站交互的
# 頭文件(這種工具很多瀏覽器是自帶的),我用的是firefox的firebug插件。.鏈枃鍘熷壋鑷�1point3acres璁哄潧
header = {'Host': 'scholar.google.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:26.0) Gecko/20100101 Firefox/26.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive'}
# 建立連接請求,這時google的服務器返回頁面信息給con這個變量,con是一個對象
req = urllib2.Request(url, headers = header) 
con = urllib2.urlopen( req )
# 對con這個對象調用read()方法,返回的是html頁面,也就是有html標簽的純文本
doc = con.read()
# 關閉連接。就像讀完文件要關閉文件一樣,如果不關閉有時可以、但有時會有問題,
# 所以作為一個守法的好公民,還是關閉連接好了。
con.close()

以上的代碼就把在google scholar上查詢On Random Graph的結果返回到doc這個變量中了,這個和你打開google scholar搜索On Random Graph,然后將網頁右鍵保存的效果是一樣的。


步驟三、解析網頁
上面的步驟得到了網頁的信息,但是包括了html標簽,你要把這些標簽去掉,然后從html文本中整理出有用的信息,
你需要解析這個網頁。
解析網頁的方法:
(1) 正則表達式。正則表達式很有用,熟悉它節省很多的時間,有時候清洗數據不用寫腳本或者在數據庫上查詢,直接在notepad++上用正則表達式組合使用就行了。如何學習正則表達式建議看:正則表達式30分鍾入門教程,鏈接:http://deerchao.net/tutorials/regex/regex.htm. more info on 1point3acres.com
(2) BeautifulSoup模塊。BeautifulSoup是一個很強大的模塊,能把html文件解析成一個對象,這個對象是一棵樹。我們都知道html文件是樹狀的,比如 body -> table -> tbody -> tr,對於tbody這個節點,有很多個tr的子節點。BeautifulSoup可以很方便的取到特定的節點,對單個節點也可以取它的sibling node。網上有很多相關的說明,這里不細說,只演示簡單的代碼:
(3) 上面兩種方法結合使用。

# 導入BeautifulSoup模塊和re模塊,re是python中正則表達式的模塊
import BeautifulSoup
import re
# 生成一個soup對象,doc就是步驟二中提到的
soup = BeautifulSoup.BeautifulSoup(doc)
# 抓取論文標題,作者,簡短描述,引用次數,版本數,引用它的文章列表的超鏈接
# 這里還用了一些正則表達式,不熟悉的先無知它好了。至於'class' : 'gs_rt'中
# 'gs_rt'是怎么來的,這個是分析html文件肉眼看出來的。上面提到的firebug插件
# 讓這個變的很簡單,只要一點網頁,就可以知道對應的html 標簽的位置和屬性,
# 相當好用。
paper_name = soup.html.body.find('h3', {'class' : 'gs_rt'}).text
paper_name = re.sub(r'\[.*\]', '', paper_name) # eliminate '[]' tags like '[PDF]'
paper_author = soup.html.body.find('div', {'class' : 'gs_a'}).text. from: 1point3acres.com/bbs 
paper_desc = soup.html.body.find('div', {'class' : 'gs_rs'}).text
temp_str = soup.html.body.find('div', {'class' : 'gs_fl'}).text
temp_re = re.match(r'[A-Za-z\s]+(\d*)[A-Za-z\s]+(\d*)', temp_str)
citeTimes = temp_re.group(1)
versionNum = temp_re.group(2)
if citeTimes == '':
  citeTimes = '0'
if versionNum == '':
  versionNum = '0'
citedPaper_href = soup.html.body.find('div', {'class' : 'gs_fl'}).a.attrs[0][1]

這些都是我在一個分析citation network的項目的代碼。順便一提,我從google scholar上抓取paper的信息以及引用列表的信息,訪問了大概1900次左右的時候給google block了,導致這個片區的ip一時無法登陸google scholar。


步驟四:存取數據
好不容易抓了數據,現在只是存儲在內存中,必須保存起來才能利用。
(1) 最簡單的方法之把數據寫進txt文件中,Python中可以用如下代碼實現:

# 打開文件webdata.txt,生成對象file,這個文件可以是不存在的,參數a表示往里面添加。
# 還有別的參數,比如'r'只能讀但不能寫入,'w'可以寫入但是會刪除原來的記錄等等
file = open('webdata.txt','a')
line = paper_name + '#' + paper_author + '#' + paper_desc + '#' + citeTimes + '\n'
# 對象file的write方法將字符串line寫入file中
file = file.write(line)
# 再一次的,做個隨手關閉文件的好青年
file.close()

這樣,就把從網頁上抓到並且解析了的數據存儲到本地了,是不是很簡單?

(2) 當然,你也可以不寫入txt文件中,而是直接連接數據庫,python中的MySQLdb模塊可以實現和MySQL數據庫的交互,把數據直接倒到數據庫里面,與MySQL數據庫建立鏈接的邏輯和與網站服務器建立鏈接的邏輯差不多。如果之前有學習過數據庫,學習用MySQLdb模塊實現和數據庫的交互是很簡單的;如果沒有,則要借助在coursera\stanford openEdX平台上都有開設的Introduction to Database來系統學習,w3school用來參考或者當成手冊。
Python能夠鏈接數據庫的前提是數據庫是開着的,我用的是 win7 + MySQL5.5,數據庫在本地。

%可以用cmd開啟數據庫,啟動命令是:
net start mysql55
%關閉命令是:
net stop mysql55

使用MySQLdb模塊代碼示例:

# 導入 MySQLdb模塊
import MySQLdb
# 和服務器建立鏈接,host是服務器ip,我的MySQL數據庫搭建在本機,默認的是127.0.0.1,
# 用戶、密碼、數據庫名稱對應着照輸就行了,默認的端口號是3306,charset是編碼方式,
# 默認的是utf8(也有可能是gbk,看安裝的版本)。. visit 1point3acres.com for more.
conn = MySQLdb.connect(host='127.0.0.1', user='root', passwd='yourPassword', db='dbname', port=3306, charset='utf8'). 鍥磋鎴戜滑@1point 3 acres
# 建立cursor
cur = conn.cursor()# 通過對象cur的execute()方法執行SQL語句
cur.execute("select * from citeRelation where paperName = 'On Random Graph'")
# fetchall()方法獲得查詢結果,返回的是一個list,可以直接這樣查詢:list[i][j],
# i表示查詢結果中的第i+1條record,j表示這條記錄的第j+1個attribute(別忘了python從0開始計數)
list = cur.fetchall()
# 也可以進行delete,drop,insert,update等操作,比如
sql = "update studentCourseRecord set fail = 1 where studentID = '%s' and semesterID = '%s' and courseID = '%s'" %(studentID,course[0],course[1])
cur.execute(sql)
# 與查詢不同的是,執行完delete,insert,update這些語句后必須執行下面的命令才能成功更新數據庫
conn.commit()
# 一如既往的,用完了之后記得關閉cursor,然后關閉鏈接
cur.close()
conn.close()

這樣就實現了Python和數據庫之間的交互。除了MySQL數據庫外,python的PyGreSQL模塊可以支持postgreSQL數據庫,道理類似的。還有,如果你的網頁里面包含了中文,設置編碼格式會非常的麻煩,需要服務器、Python、數據庫和數據庫界面采用相同的編碼格式才能不出現亂碼,如果真的出現了中文亂碼的問題,請相信,你不是一個人!!去google一下吧,成千上萬的人碰到過這種問題。

關於編碼的問題,附一篇我看到的博文<python編碼問題總結>:
http://www.xprogrammer.com/1258.html

后記:
上面介紹了抓取網頁數據的方法,抓取數據只是一小步,如何分析數據就是大學問了,歡迎討論。
上面有什么地方講不清楚的,歡迎交流。

特別注意:
大規模抓取網站會給網站的服務器帶來很大的壓力,盡量選擇服務器相對輕松的時段(比如凌晨)。網站很多,不要拿一畝三分地來做試驗。
Python的time模塊的sleep()方法可以讓程序暫停一段時間,比如time.sleep(1)讓程序運行到這里的時候暫停1秒。適時地暫停可以緩解服務器的壓力,也可以保護自己的硬盤,正好碼久了睡個覺,或者去趟gym,結果就出來了。


免責聲明!

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



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