python爬蟲實例之慢速VOA網站的文章爬取
程序的需求分析
- 爬取前兩頁所有文章的名字
- 將文章的名字按照需要輸出在控制檯
- 同時將每一篇文章保存在對應的以文章名爲題的文檔中
前期分析
-
首先來看看你的網頁的概況,網址是:https://www.51voa.com/Technology_Report_1.html
-
這是首頁
-
再看看對應的網頁原碼
所有的文章名稱都是在"< a >…<\a>"標籤中的,並且這個a標籤不同於別的a標籤,都有target屬性,並且所有的target屬性都是“_blank”,故直接通過對應查找標籤的findall函數直接查找所有的標籤,直接獲取標籤的string值
<a href="/VOA_Special_English/how-effective-are-online-symptom-checkers-84580.html" target=_blank>How Effective Are Online Symptom Checkers?</a>
<a href="/VOA_Special_English/coronavirus-crisis-changes-the-world-of-autonomous-vehicles-84579.html" target=_blank>Coronavirus Crisis Changes the World of Autonomous Vehicles</a>
- 在源碼頁面直接點擊對應的a標籤的href屬性值,直接跳轉到對應的文章的頁面,
如下
- 然後,再查看對應的源代碼,查找對應的文章在什麼位置
有兩處地方都有對應的文章,一方面< p > … < \p >標籤內如下圖
另外一方面,“[00:00.00]…”可以用正則表達式直接搜索,然後將獲取到的結果用“]”進行劃分,然後將後繼部分保存在文檔裏就行了,對應的正則表達式r’ [ [\d:.] *[ \ w ] * \ ] ’
- 最後來看看翻頁的方式,"Report_"關鍵字進行連接
程序編寫
-
第一步確定大概的步驟
- 獲取對應鏈接的html文本,基本的框架不變getHTMLText(url)
- 對html文本進行解析,獲取標題,獲取連接parserHTML(text,ilt)
- 對某一篇文章所在得具體的頁面進行瀏覽,保存文章storeText(path,url)
- 將對應的文章標題的信息輸出到對應的控制檯printMessage(ilt)
- 最後再用main()函數將所有的函數進行連接
-
逐步完善各個步驟
import re
import requests
from bs4 import BeautifulSoup
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ''
# 分解頁面
def parseHTMLText(text,ilt):
soup = BeautifulSoup(text, 'html.parser')
aTag = list(soup.find_all('a', target='_blank'))
path = 'D:\SpiderTest'
for a in range(len(aTag)):
ilt.append(aTag[a].string)
path1 = path + '\ ' + aTag[a].string + '.txt'
url2 = 'https://www.51voa.com/' + aTag[a].attrs['href']
storeText(path1, url2)
# 保存頁面
def storeText(path,url):
text = getHTMLText(url)
soup = BeautifulSoup(text,'html.parser')
p = soup.find_all('p')
# 這裏返回的不是對應的的string類型,是沒有辦法直接寫入的
path = path.replace(' ','')
path = path.replace('?','')
with open(path,'w') as f:
for i in range(len(p)):
f.write(str(p[i].string))
# 將對應的信息輸出到控制檯
def printMessage(ilt):
text = '{:<10}\t{:<20}'
print(text.format("序號", "文章名"))
count = 1
for i in ilt:
print(text.format(count, i))
count += 1
# 用main函數將所有的程序連接起來
def main():
url = 'https://www.51voa.com/Technology_Report_1.html'
i = 4
res = list()
for i in range(2,4):
text = getHTMLText(url)
parseHTMLText(text,res)
r = 'Report_'+str(i)
target = re.findall(r'Report_\d',url)
url = url.replace(target[0],r,1)
printMessage(res)
main()
結果
注意點——就是我修改的bug
- < tag > string < /tag >其中的string雖然真正調用的時候使用tag.string方法,但是不是string類型的,是NavigableString類型的,詳見下圖。而用IO流的時候,又只可以寫入string類型,所以這裏注意!
- 調用BeautifulSoup時,記住要加上解析的格式,我就是老是忘記BeautifulSoup(text,‘html.parser’)
- IO流中的文件的路徑是有特殊的要求的,不能有空格,不可以有問號,所以要講對應的特殊的不合法的字符完全清除
- 對於try——except的使用要注意,如果將文件讀寫放入其中,那麼對應的就不會報錯,但是隻會循環一次
- 打開讀寫文件,比對文章之後發現,有很多的none,說明並沒有將所有的文章內容全部都爬取到對應的文檔內容中,有些內容變成了None。
通過分析發現,只要p標籤內部有別的非文本的內容,會自動讀取爲None
所以現在有以下幾種解決思路:
- 對其進行寫入的時候進行一定的篩選和判定,如果所有的p標籤有對應的子孫類,那就對其單獨操作,沒有直接寫入
- 採用正則表達式進行匹配,換一個地方進行匹配。
- 採用第二種方式修改如下
# 保存頁面
def storeText(path,url):
text = getHTMLText(url)
regex = re.compile(r'[\[]{1}[\d\:\.]+[\]]{1}[a-zA-Z+\s+\.+\"\"\'\'\,+]+')
reslist = regex.findall(text)
# 這裏返回的不是對應的的string類型,是沒有辦法直接寫入的
path = path.replace(' ','')
path = path.replace('?','')
count = 0
with open(path,'a+') as f:
for i in reslist:
f.write(str(i.split(']')[1]))
結果如下,是一篇完整的文章!!!
- 其實,還有一種用方法,你仔細看文章外面有個特殊的標籤,直接把標籤的內容寫入就行了
總結:
- 最然很晚了,但是我還是很高興的,我終於寫出來了,終於寫出來了
- 很有意思的一次實踐,我該繼續往下學習了,我還要學習數據分析,自己爬取數據,然後自動分析,豈不是很棒!!!