Python博客園-獲取某個博主所有文章的URL列表
首先,我們來分析一下,在博主的首頁里,每個文章的標題在網頁源碼中是什么樣子的。
【插入圖片,文章標題1】
【插入圖片,文章標題2】
通過這兩個圖片我們可以看出,博文標題所在的標簽為,並且具有class屬性為"postTitle2",其href屬性就指向這篇博文的地址。
如下面代碼所示:
<a id="homepage1_HomePageDays_DaysList_ctl01_DayList_TitleUrl_0" class="postTitle2"
href="http://www.cnblogs.com/over140/p/5462580.html">【Swift 2.2】iOS開發筆記(三)</a>
那么,我們的思路就可以是這樣的:
找到所有展示博文標題的a標簽,獲取a標簽的href屬性,那么就可以得到所有文章的url列表。
但是目前存在一個問題,所有的博文標題沒有在同一個頁面中展示出來。
【插入圖片,18頁】
可以看出,農民伯伯的文章一共有18頁,每一頁中存在一些文章標題和摘要,那么我們就要遍歷這18頁,來獲取所有的博文標題。
如何得到這18頁的url呢?
【插入圖片,每頁url】
通過分析每一頁的url,我們確定只有page=后面的頁碼是改變的,從1-18,得到這18個url的話,就能得到所有文章的標題了。
http://www.cnblogs.com/over140/default.html?page=2
實測代碼如下,還是使用正則表達式,將所有的博文url都匹配了出來。
相比上篇文章,做了一些改進,獲取html源碼的代碼,我定義成了一個方法,這樣調用起來方便多了。
關於正則表達式如何匹配處URL的內容,請查看我之前的爬蟲入門文章,關於正則進行了簡單的講解,應該夠我們應對一般情況了。
import urllib.request
import re
#該作者的博文一共有多少頁
pageNo=18
#后面需要添加頁碼
url='http://www.cnblogs.com/over140/default.html?page='
def get_html(url):
'''
返回對應url的網頁源碼,經過解碼的內容
:param url:
:return:
'''
req = urllib.request.Request(url)
resp = urllib.request.urlopen(req)
html_page = resp.read().decode('utf-8')
return html_page
def get_Urls(url,pageNo):
'''
根據url,pageNo,能夠返回該博主所有的文章url列表
:param url:
:param pageNo:
:return:
'''
total_urls=[]
for i in range(1,pageNo+1):
url_1=url+str(i)
html=get_html(url_1)
title_pattern=r'<a.*class="postTitle2".*href="(.*)">'
urls=re.findall(title_pattern,html)
for url_ in urls:
total_urls.append(url_)
#print(total_urls.__len__())
return total_urls
還是對上面的get_Urls方法做一些講解吧。
total_urls是我們定義的存儲所有url的列表,這個對象作為結果返回;
#這句話,是生成這18頁中,每一頁的url地址
url_1=url+str(i)
#如前所述,獲取指定url下的網頁源碼,用於后面的解析
html=get_html(url_1)
#首先創建正則表達式,注意中間的括號,這個分組里面的內容才是我們想要的
title_pattern=r'<a.*class="postTitle2".*href="(.*)">'
urls=re.findall(title_pattern,html)
我覺得差不多了。既然我們都已經獲取到所有文章的url列表了,而不一步到位,將所有的文章都保存下來呢。
首先展示代碼,talk is cheap, show you the code。
import urllib.request
import re
from bs4 import BeautifulSoup
#該作者的博文一共有多少頁
pageNo=18
#這是要訪問的某一篇文章的地址
url_single='http://www.cnblogs.com/over140/p/4440137.html'
#后面需要添加頁碼
url='http://www.cnblogs.com/over140/default.html?page='
#博主大大的名字
author='over140'
def get_html(url):
'''
返回對應url的網頁源碼,經過解碼的內容
:param url:
:return:
'''
req = urllib.request.Request(url)
resp = urllib.request.urlopen(req)
html_page = resp.read().decode('utf-8')
return html_page
def get_title(url):
'''
獲取對應url下文章的標題
:param url:
:return:
'''
html_page = get_html(url)
title_pattern = r'(<a.*id="cb_post_title_url".*>)(.*)(</a>)'
title_match = re.search(title_pattern, html_page)
title = title_match.group(2)
return title
def get_Body(url):
'''
獲取對應url的文章的正文內容
:param url:
:return:
'''
html_page = get_html(url)
soup = BeautifulSoup(html_page, 'html.parser')
div = soup.find(id="cnblogs_post_body")
return div.get_text()
def save_file(url):
'''
根據url,將文章保存到本地
:param url:
:return:
'''
title=get_title(url)
body=get_Body(url)
filename=author+'-'+title+'.txt'
with open(filename, 'w', encoding='utf-8') as f:
f.write(body)
def get_Urls(url,pageNo):
'''
根據url,pageNo,能夠返回該博主所有的文章url列表
:param url:
:param pageNo:
:return:
'''
total_urls=[]
for i in range(1,pageNo+1):
url_1=url+str(i)
html=get_html(url_1)
title_pattern=r'<a.*class="postTitle2".*href="(.*)">'
urls=re.findall(title_pattern,html)
for url_ in urls:
total_urls.append(url_)
print(total_urls)
return total_urls
def save_files(url,pageNo):
'''
根據url和pageNo,保存博主所有的文章
:param url:
:param pageNo:
:return:
'''
totol_urls=get_Urls(url,pageNo)
for url_ in totol_urls:
save_file(url_)
if __name__=='__main__':
save_files(url,pageNo)
大家有沒有覺得上面的代碼,比昨天的看起來要好的多了,直觀好懂。
因為我將很多零碎的語句都轉換成了方法,通過調用來重復使用代碼,省了很多力氣。
接下來,我嘗試運行這段代碼,但是很快就報錯了。
【插入圖片,報錯信息1,文件名問題】
原因是生成的filename中,存在/這種天理不容的字符。
想辦法解決唄,這時肯定要對filename進行調整了。
if '/' in filename:
filename=filename.replace('/','+')
if '\\' in filename:
filename=filename.replace('\\','+')
這種錯誤盡量解決就可以啦,但是很多情況下還會有個別錯誤超出我們的預期,那么更直接的辦法是在save_files里面做文章,
def save_files(url,pageNo):
'''
根據url和pageNo,保存博主所有的文章
:param url:
:param pageNo:
:return:
'''
totol_urls=get_Urls(url,pageNo)
for url_ in totol_urls:
try:
save_file(url_)
except:
pass
如果保存單個文件出錯,那么就隨他去吧,pass掉就好了。
實測上述代碼可以完整運行了。
但是我們得到的內容只有文本,這種方法適合去爬一些小說啊,評論之類的內容。
如果想得到博文中的圖片、代碼、音頻視頻等內容,還需要換一種方法。
不要急,我們慢慢就會講到的。