手把手教你用python抓取網頁

http://www.1point3acres.com/bbs/thread-83337-1-1.html

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

**. more info on 1point3acres.com

已經熟悉Python的直接跳到步驟二。

Python是門比較容易入門的編程語言,如何上手視編程基礎而定。
(1) 如果有一定編程的基礎,建議看google's python class,
鏈接https://developers.google.com/edu/python/?hl=zh-CN&csw=1
這個是一個為期兩天的短期培訓課程(當然,是兩個全天),大概是七個視頻,每個視頻之后給編程作業(yè),每個作業(yè)一個小時之內可以完成。這是我學習python的第二門課(第一門是codecademy的python,很早之前看的,很多內容都記不得了),當時每天看視頻+編程作業(yè)一個多小時,六天弄完,效果還不錯,用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,這些資源也是挺不錯的,但是編程量太少,初學者還是系統(tǒng)的跟課、多練練手來打好基礎吧。
當然,每個人的偏好不同,我推薦的不一定適合你??梢韵瓤纯催@個帖子
【長期加分貼】介紹你上過的公開課

里面其他人是怎么說的,或者上coursetalk.org
看看課程評論,再決定吧。

步驟二:學會如何與網站建立鏈接,得到網頁數(shù)據(jù)。

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

導入模塊 urllib2

import urllib2

隨便查詢一篇文章,比如On random graph。對每一個查詢google

scholar都有一個url,這個url形成的規(guī)則是要自己分析的。

query = 'On+random+graph'. from: 1point3acres.com/bbs

url = 'http://scholar.google.com/scholar?hl=en&q=' + query + '&btnG=&as_sdt=1%2C5&as_sdtp='

設置頭文件。抓取有些的網頁不需要專門設置頭文件,但是這里如果不設置的話,

google會認為是機器人不允許訪問。另外訪問有些網站還有設置Cookie,這個會相對復雜一些,

這里暫時不提。關于怎么知道頭文件該怎么寫,一些插件可以看到你用的瀏覽器和網站交互的

頭文件(這種工具很多瀏覽器是自帶的),我用的是firefox的firebug插件。

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) 正則表達式。正則表達式很有用,熟悉它節(jié)省很多的時間,有時候清洗數(shù)據(jù)不用寫腳本或者在數(shù)據(jù)庫上查詢,直接在notepad++上用正則表達式組合使用就行了。如何學習正則表達式建議看:正則表達式30分鐘入門教程,鏈接:http://deerchao.net/tutorials/regex/regex.htm
(2) BeautifulSoup模塊。BeautifulSoup是一個很強大的模塊,能把html文件解析成一個對象,這個對象是一棵樹。我們都知道html文件是樹狀的,比如 body -> table -> tbody -> tr,對于tbody這個節(jié)點,有很多個tr的子節(jié)點。BeautifulSoup可以很方便的取到特定的節(jié)點,對單個節(jié)點也可以取它的sibling node。網上有很多相關的說明,這里不細說,只演示簡單的代碼:
(3) 上面兩種方法結合使用。

導入BeautifulSoup模塊和re模塊,re是python中正則表達式的模塊

import BeautifulSoup

import re

生成一個soup對象,doc就是步驟二中提到的

soup = BeautifulSoup.BeautifulSoup(doc)

抓取論文標題,作者,簡短描述,引用次數(shù),版本數(shù),引用它的文章列表的超鏈接

這里還用了一些正則表達式,不熟悉的先無知它好了。至于'class' : 'gs_rt'中

'gs_rt'是怎么來的,這個是分析html文件肉眼看出來的。上面提到的firebug插件

讓這個變的很簡單,只要一點網頁,就可以知道對應的html 標簽的位置和屬性,

相當好用。. visit 1point3acres.com for more.

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

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了,導致這個片區(qū)的ip一時無法登陸google scholar。

步驟四:存取數(shù)據(jù)

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

打開文件webdata.txt,生成對象file,這個文件可以是不存在的,參數(shù)a表示往里面添加。

還有別的參數(shù),比如'r'只能讀但不能寫入,'w'可以寫入但是會刪除原來的記錄等等

file = open('webdata.txt','a')

line = paper_name + '#' + paper_author + '#' + paper_desc + '#' + citeTimes + '\n'

# 對象file的write方法將字符串line寫入file中

file = file.write(line)-google 1point3acres

# 再一次的,做個隨手關閉文件的好青年

file.close()

這樣,就把從網頁上抓到并且解析了的數(shù)據(jù)存儲到本地了,是不是很簡單?
(2) 當然,你也可以不寫入txt文件中,而是直接連接數(shù)據(jù)庫,python中的MySQLdb模塊可以實現(xiàn)和MySQL數(shù)據(jù)庫的交互,把數(shù)據(jù)直接倒到數(shù)據(jù)庫里面,與MySQL數(shù)據(jù)庫建立鏈接的邏輯和與網站服務器建立鏈接的邏輯差不多。如果之前有學習過數(shù)據(jù)庫,學習用MySQLdb模塊實現(xiàn)和數(shù)據(jù)庫的交互是很簡單的;如果沒有,則要借助在coursera[stanford](http://www.1point3acres.com/stanford-ee-ms-admission-letter/) openEdX平臺上都有開設的Introduction to Database來系統(tǒng)學習,w3school用來參考或者當成手冊。
Python能夠鏈接數(shù)據(jù)庫的前提是數(shù)據(jù)庫是開著的,我用的是 win7 + MySQL5.5,數(shù)據(jù)庫在本地。

%可以用cmd開啟數(shù)據(jù)庫,啟動命令是:
net start mysql55 [1point3acres.com/bbs](http://1point3acres.com/bbs)

%關閉命令是:

net stop mysql55

使用MySQLdb模塊代碼示例:

# 導入 MySQLdb模塊

import MySQLdb

# 和服務器建立鏈接,host是服務器ip,我的MySQL數(shù)據(jù)庫搭建在本機,默認的是127.0.0.1,

# 用戶、密碼、數(shù)據(jù)庫名稱對應著照輸就行了,默認的端口號是3306,charset是編碼方式,

# 默認的是utf8(也有可能是gbk,看安裝的版本)。
conn = MySQLdb.connect(host='127.0.0.1', user='root', passwd='yourPassword', db='dbname', port=3306, charset='utf8')

# 建立cursor

cur = conn.cursor()

# 通過對象cur的execute()方法執(zhí)行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開始計數(shù))

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)

# 與查詢不同的是,執(zhí)行完delete,insert,update這些語句后必須執(zhí)行下面的命令才能成功更新數(shù)據(jù)庫

conn.commit()

# 一如既往的,用完了之后記得關閉cursor,然后關閉鏈接

cur.close()

conn.close()

這樣就實現(xiàn)了Python和數(shù)據(jù)庫之間的交互。除了MySQL數(shù)據(jù)庫外,python的PyGreSQL模塊可以支持postgreSQL數(shù)據(jù)庫,道理類似的。還有,如果你的網頁里面包含了中文,設置編碼格式會非常的麻煩,需要服務器、Python、數(shù)據(jù)庫和數(shù)據(jù)庫界面采用相同的編碼格式才能不出現(xiàn)亂碼,如果真的出現(xiàn)了中文亂碼的問題,請相信,你不是一個人?。∪oogle一下吧,成千上萬的人碰到過這種問題。
關于編碼的問題,附一篇我看到的博文<python編碼問題總結

:

http://www.xprogrammer.com/1258.html

后記:

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

**特別注意:

大規(guī)模抓取網站會給網站的服務器帶來很大的壓力,盡量選擇服務器相對輕松的時段(比如凌晨)。網站很多,不要拿一畝三分地來做試驗。

Python的time模塊的sleep()方法可以讓程序暫停一段時間,比如time.sleep(1)讓程序運行到這里的時候暫停1秒。適時地暫停可以緩解服務器的壓力,也可以保護自己的硬盤,正好碼久了睡個覺,或者去趟gym,結果就出來了。
**

更新:
2014年2月15日,更改了幾處打字錯誤;添加了相關課程鏈接;增加了udacity CS101的介紹;增加了MySQLdb模塊的介紹。
2014年2月16日,增加了介紹編碼方式的博文鏈接。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • # Python 資源大全中文版 我想很多程序員應該記得 GitHub 上有一個 Awesome - XXX 系列...
    小邁克閱讀 3,122評論 1 3
  • Python語言特性 1 Python的函數(shù)參數(shù)傳遞 看兩個如下例子,分析運行結果: 代碼一: a = 1 def...
    伊森H閱讀 3,175評論 0 15
  • 來源:k6k4 答案參考:Spring常見面試題 1、Spring框架有哪些優(yōu)點? 2、什么是Spring的內部b...
    CodeYangX閱讀 3,091評論 0 3
  • 覺察一小步,成長一大步。 第一個覺察:模式好可怕,看到了就要去調整,也給自己一個時間跟過程吧。畢竟我是人不是神。 ...
    Aimee王艾美閱讀 174評論 0 0

友情鏈接更多精彩內容