公眾號(hào)的第一篇文章,就先來(lái)介紹一下我做的最多的也是最簡(jiǎn)單的新聞爬蟲(chóng)吧。這個(gè)爬蟲(chóng)本身是用java寫(xiě)的,搭載在我之前項(xiàng)目的服務(wù)器上向臀,今天用python實(shí)現(xiàn)一下。這個(gè)爬蟲(chóng)我也給別人講過(guò)很多次莫矗,在雙創(chuàng)之星的舞臺(tái)上講過(guò)飒硅,在新生導(dǎo)航課上講過(guò)(兩次)砂缩,在課堂上講過(guò)。其實(shí)現(xiàn)在回頭看一下這個(gè)爬蟲(chóng)真的很low很簡(jiǎn)單三娩,但好歹也是我花了很久學(xué)習(xí)的庵芭,今天就系統(tǒng)的用python來(lái)實(shí)現(xiàn)一下吧。
新聞爬蟲(chóng)
- 單個(gè)網(wǎng)頁(yè)信息爬取
- 多個(gè)網(wǎng)頁(yè)鏈接爬取
- 整合模塊代碼
1.單個(gè)網(wǎng)頁(yè)信息爬取
1.1獲取目標(biāo)網(wǎng)址信息
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/info/1009/7267.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
print(req.text)
我選取的網(wǎng)址是華師信管官網(wǎng)雀监。在這段代碼中我們通過(guò)一個(gè)requests.get()
來(lái)獲取了目標(biāo)對(duì)象双吆,你可以把這一步理解為用瀏覽器打開(kāi)了一個(gè)網(wǎng)頁(yè)。這里記住把編碼格式通過(guò)req.encoding
進(jìn)行統(tǒng)一会前,避免出現(xiàn)亂碼的情況好乐。最后一行是輸出這個(gè)網(wǎng)頁(yè)的源碼
1.2.提取目標(biāo)網(wǎng)址信息
我們使用瀏覽器打開(kāi)具體的網(wǎng)頁(yè),查看我們需要的信息
谷歌瀏覽器可以直接通過(guò)檢查查看到我們需要的信息在哪里
我們可以看到我們所需要的文本信息都在
class="sub_r_con sub_r_intro"
的div
中瓦宜。到這里我們要明確下我們所需要的信息到底是什么(其實(shí)這一步在你寫(xiě)爬蟲(chóng)前就要確定好)蔚万。這里我們需要的是新聞標(biāo)題、日期临庇、作者反璃、正文,那么下面我們就要逐個(gè)擊破
1.2.1獲取標(biāo)題
同樣的我們檢查標(biāo)題所在的位置
我們發(fā)現(xiàn)這個(gè)標(biāo)題在
<h1>
中假夺,下面通過(guò)代碼來(lái)獲取
from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/info/1009/7267.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
title = bf.find_all('h1') #獲取頁(yè)面所有的h1標(biāo)簽
print(title)
一行一行來(lái)讀代碼其實(shí)很好理解淮蜈,前面我們獲取了網(wǎng)頁(yè)的源代碼。通過(guò)bf = BeautifulSoup(html,'lxml')
來(lái)對(duì)網(wǎng)頁(yè)進(jìn)行解析已卷,講解析后的網(wǎng)頁(yè)結(jié)構(gòu)賦予bf
尺铣。這里說(shuō)明一下腐螟,lxml是一個(gè)參數(shù)乡范,后面我會(huì)在專(zhuān)門(mén)學(xué)習(xí)BeautifulSoup的板塊來(lái)學(xué)習(xí)偎捎。
我們將包含所有的<h1>
模塊賦予給title
,這一步通過(guò)bf.find_all()
來(lái)實(shí)現(xiàn)闺魏,這個(gè)也很好理解未状,解析后的網(wǎng)頁(yè)分模塊賦予給了bf
,我們通過(guò)bf.find_all()
這一操作找到<h1>
的標(biāo)簽并將其賦予給title
但當(dāng)我們輸出這段代碼的時(shí)候問(wèn)題來(lái)了
這是因?yàn)檎麄€(gè)頁(yè)面不止一個(gè)
<h1>
標(biāo)簽析桥,只有第三個(gè)標(biāo)簽符合我們的要求,只需要對(duì)代碼稍作修改就可以實(shí)現(xiàn)最終想要達(dá)到的效果
from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/info/1009/7267.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
titles = bf.find_all('h1') #獲取頁(yè)面所有的h1標(biāo)簽
title = titles[2].text#提取最后一個(gè)節(jié)點(diǎn)轉(zhuǎn)換為文本
print(title)
1.2.2獲取日期和作者
同樣我們找到日期和作者所在的div
標(biāo)簽艰垂,發(fā)現(xiàn)它的類(lèi)別為class_="cz"
泡仗,進(jìn)行提取。
from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/info/1009/7267.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
author_date = bf.find_all('div',class_="cz") #獲取頁(yè)面的作者和日期
print(author_date[0].text)
這里多說(shuō)一句猜憎,即使模塊中只含有一個(gè)標(biāo)簽娩怎,也得用列表的形式表示出元素,就像這里的author_date
一樣胰柑,不然會(huì)報(bào)錯(cuò)
1.2.3獲取正文
相信你前面都實(shí)現(xiàn)了的話(huà)截亦,這一步你也會(huì)很熟練了爬泥。首先找到正文所在div
為類(lèi)別class="normal_intro"
,修改一下前面的代碼即可
from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/info/1009/7267.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
article = bf.find_all('div',class_="normal_intro") #獲取頁(yè)面正文
print(article[0].text)
2.多個(gè)網(wǎng)頁(yè)鏈接爬取
上面只是對(duì)于某一個(gè)新聞頁(yè)面的信息爬取崩瓤,而我們需要做到的是袍啡,給定華師信管的網(wǎng)址,能自動(dòng)爬取上面所有的網(wǎng)址
2.1獲取翻頁(yè)鏈接
首先我們想一個(gè)問(wèn)題却桶,我們自己在瀏覽新聞網(wǎng)站時(shí)境输,需要進(jìn)行翻頁(yè),同樣我們的爬蟲(chóng)也需要獲取到目標(biāo)網(wǎng)頁(yè)的翻頁(yè)地址
這里需要兩步:
- 識(shí)別翻頁(yè)的
<a>
標(biāo)簽 - 提取網(wǎng)址
檢查源代碼發(fā)現(xiàn)翻頁(yè)標(biāo)簽鏈接中包含xydt/
這就好辦了颖系,我們通過(guò)下面的代碼可以得到翻頁(yè)的鏈接
from bs4 import BeautifulSoup
import re
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/xwdt/xydt.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
fan_linklist = [] #存入翻頁(yè)地址
for x in bf.find_all('a',href = re.compile('xydt/')): #找到目標(biāo)a標(biāo)簽
link = x.get('href') #提取鏈接
if link:
fan_linklist.append(link) #存入列表
print(fan_linklist)
2.2獲取新聞鏈接地址
通過(guò)上面的代碼嗅剖,你只需要找到新聞鏈接標(biāo)簽特點(diǎn)然后修改代碼即可,細(xì)心檢查可以發(fā)現(xiàn)嘁扼,新聞鏈接都含有info/
from bs4 import BeautifulSoup
import re
import requests
if __name__ == "__main__":
target = 'http://imd.ccnu.edu.cn/xwdt/xydt.htm' #目標(biāo)網(wǎng)址
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
xinwen_linklist = [] #存入翻頁(yè)地址
for x in bf.find_all('a',href = re.compile('info/')): #找到目標(biāo)a標(biāo)簽
link = x.get('href') #提取鏈接
if link:
xinwen_linklist.append(link) #存入列表
print(xinwen_linklist)
3.整合代碼
好了信粮,做到這步前面都能實(shí)現(xiàn)的話(huà),你已經(jīng)全部明白原理了趁啸,嗯....你沒(méi)有聽(tīng)錯(cuò)蒋院,只是明白原理了,寫(xiě)程序最麻煩的就是調(diào)試和修改莲绰,所以你后面的工作量可能是你前面的幾倍
我們?cè)賮?lái)過(guò)一遍這個(gè)爬蟲(chóng)的邏輯
- 獲取當(dāng)前地址的翻頁(yè)地址欺旧,也就是下一頁(yè)地址。此步驟重復(fù)蛤签,直至獲取網(wǎng)站全部的翻頁(yè)地址
- 獲取每一個(gè)地址中的新聞鏈接
- 提取新聞信息
這其中還有一點(diǎn)我們要注意辞友,就是第1,2步我們都要設(shè)置一個(gè)去重程序震肮,即除去反復(fù)爬取的地址称龙,這樣保證效率也保護(hù)電腦,它好你也好
下面就動(dòng)手實(shí)現(xiàn)啦戳晌!
另外需要說(shuō)明一下鲫尊,上面的代碼片段重在原理,最終的爬蟲(chóng)代碼和上面的代碼可能稍有出入沦偎,但其實(shí)都是萬(wàn)變不離其宗
from bs4 import BeautifulSoup
import re
import requests
class downloader(object):
def __init__(self):
self.target = 'http://imd.ccnu.edu.cn/xwdt/xydt.htm' #目標(biāo)網(wǎng)址
"""
函數(shù)說(shuō)明:獲取翻頁(yè)地址
Parameters:
xiayiye - 下一頁(yè)地址(string)
Returns:
fanye - 當(dāng)前頁(yè)面的翻頁(yè)地址(list)
"""
def get_fanye_url(self,target):
req = requests.get(target) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
fanye = []
for x in bf.find_all('a',class_="Next"): #找到目標(biāo)a標(biāo)簽
link = x.get('href') #提取鏈接
if link:
link = link.replace('xydt/','')
link = "http://imd.ccnu.edu.cn/xwdt/xydt/" + link #將提取出來(lái)的鏈接補(bǔ)充完整
fanye.append(link) #存入列表
return fanye
"""
函數(shù)說(shuō)明:獲取新聞地址
Parameters:
fanye - 翻頁(yè)地址(string)
Returns:
xinwen_linklist - 新聞鏈接(list)
"""
def get_xinwen_url(self, fanye):
req = requests.get(fanye) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
xinwen_linklist = [] #存入翻頁(yè)地址
for x in bf.find_all('a',href = re.compile('info/')): #找到目標(biāo)a標(biāo)簽
link = x.get('href') #提取鏈接
if link:
link = "http://imd.ccnu.edu.cn" + link.replace('../..','') #將提取出來(lái)的鏈接補(bǔ)充完整
xinwen_linklist.append(link) #存入列表
return xinwen_linklist
"""
函數(shù)說(shuō)明:獲取新聞信息
Parameters:
xinwen_url - 新聞鏈接(string)
Returns:
xinwen - 新聞信息(list)
"""
def get_xinwen(self, xinwen_url):
req = requests.get(xinwen_url) #獲取對(duì)象
req.encoding = "utf-8" #設(shè)置編碼格式
html = req.text #獲得網(wǎng)頁(yè)源代碼
bf = BeautifulSoup(html,'lxml') #利用BeautifulSoup進(jìn)行解析
titles = bf.find_all('h1') #獲取頁(yè)面所有的h1標(biāo)簽
title = titles[2].text#提取最后一個(gè)節(jié)點(diǎn)轉(zhuǎn)換為文本
print("標(biāo)題:"+title)
author_date = bf.find_all('div',class_="cz")[0].text #獲取頁(yè)面的作者和日期
print("作者和日期:"+author_date)
article = bf.find_all('div',class_="normal_intro")[0].text #獲取頁(yè)面正文
print("正文:"+article)
xinwen = ["標(biāo)題:"+title,"作者和日期:"+author_date,"正文:"+article]
return xinwen
if __name__ == "__main__":
dl = downloader()
fanye = dl.get_fanye_url(dl.target)
'''
獲取全部的翻頁(yè)鏈接
'''
for x in fanye:
b = dl.get_fanye_url(x)
for w in b: #這一個(gè)循環(huán)的目的是獲取翻頁(yè)鏈接的同時(shí)去重
if w not in fanye:
fanye.append(w)
print("翻頁(yè)鏈接"+w)
'''
獲取每一個(gè)翻頁(yè)鏈接里的新聞鏈接
'''
xinwen_url = []
for x in fanye:
a = dl.get_xinwen_url(x)
for w in a: #這一個(gè)循環(huán)的目的是獲取新聞鏈接的同時(shí)去重
if w not in xinwen_url:
xinwen_url.append(w)
print("新聞地址"+w)
'''
獲取每一個(gè)新聞鏈接的新聞信息
'''
xinwen = []
for x in xinwen_url:
xinwen.append(dl.get_xinwen(x))
好了疫向,到這里這個(gè)爬蟲(chóng)就已經(jīng)寫(xiě)好了,直接復(fù)制我的代碼在編輯器里運(yùn)行豪嚎,就可以爬取華師信管官網(wǎng)的所有新聞了搔驼,可能 copy這段代碼只需要幾秒鐘,但如果能把每一步的邏輯弄明白侈询,相信你也能很快學(xué)會(huì)簡(jiǎn)單的爬蟲(chóng)的舌涨。(運(yùn)行時(shí)間大概二十分鐘,數(shù)據(jù)量1200條)
另外我還是想吐槽一下扔字,在這篇文章開(kāi)頭囊嘉,我說(shuō)了我覺(jué)得這個(gè)爬蟲(chóng)很low很簡(jiǎn)單温技,但是實(shí)際操作起來(lái)還是發(fā)現(xiàn)花了我兩天的時(shí)間,當(dāng)然兩天不是全部都在寫(xiě)程序扭粱,是在實(shí)習(xí)期間忙里偷閑寫(xiě)出來(lái)的舵鳞,看來(lái)任何事情都是不簡(jiǎn)單的,一步一步來(lái)吧
另外焊刹,歡迎關(guān)注公眾號(hào):老白和他的爬蟲(chóng)系任,這個(gè)是我的個(gè)人公眾號(hào),文章也會(huì)同步發(fā)布在簡(jiǎn)書(shū):Heisenberg_b799虐块,后面會(huì)陸續(xù)分享一些技術(shù)學(xué)習(xí)的文章俩滥,希望能對(duì)你有幫助。