爬蟲實戰【2】Python博客園-獲取某個博主所有文章的URL列表


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掉就好了。
實測上述代碼可以完整運行了。
但是我們得到的內容只有文本,這種方法適合去爬一些小說啊,評論之類的內容。
如果想得到博文中的圖片、代碼、音頻視頻等內容,還需要換一種方法。
不要急,我們慢慢就會講到的。


免責聲明!

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



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