Python爬蟲之爬取最新更新的小說網站

一、引言

這個五一假期自駕回老傢鄉下,傢裡沒裝寬帶,用手機熱點方式訪問網絡。這次回去感覺4G信號沒有以前好,通過百度查找小說最新更新並打開小說網站很慢,有時要打開好多個網頁才能找到可以正常打開的最新更新。為瞭躲懶,老猿決定利用Python爬蟲知識,寫個簡單應用自己查找小說最新更新並訪問最快的網站,花瞭點時間研究瞭一下相關報文,經過近一天時間研究和編寫,終於搞定,下面就來介紹一下整個過程。

二、關於相關訪問請求及應答報文

2.1、百度搜索請求

我們通過百度網頁的搜索框進行搜索時,提交的url請求是這樣的:

https://www.baidu.com/s?wd=搜索詞&pn=10&rn=50

請求的url為https://www.baidu.com/s,帶三個參數:

  • wd:搜索的關鍵詞
  • pn:當前需要顯示搜索結果記錄在總搜索結果的序號,如總搜索有300條記錄滿足要求,現在要求顯示第130條記錄,則pn參數值設為130即可
  • rn:每頁顯示記錄數,缺省為10條,可以自行設定,但如果設定超過50,則會強制顯示為每頁10條。

2.2、百度返回搜索結果

百度返回的搜索結果有多種方式確定,老猿認為如下方式最簡單:
以搜索小說《青萍》為例來看其中的一個返回記錄:

<h3 class="t"><a data-click="{
			'F':'778317EA',
			'F1':'9D73F1E4',
			'F2':'4CA6DE6B',
			'F3':'54E5243F',
			'T':'1620130755',
			'y':'FE7FF57A'}" 
			href="http://www.baidu.com/link?url=9LLa46B6hp69vJdLx6wOGfBpoS7BaRe8zV3oSNj_Vc2AxuU0Tz5Bl7CZlqNPobdw_BElAgaadA_HfCJMtADpyq" rel="external nofollow"  target="_blank">
			<em>青萍</em>最新章節,<em>青萍</em>免費閱讀 - 大神小說網</a>
			</h3>

整個搜索返回的結果在一個h3的標簽內,返回的搜索結果對應url在a標簽內,具體url由href來指定。這裡返回的url實際上是一個百度重定向的地址,可以通過打開該url訪問對應網站,並通過返回響應消息獲取真正網站的URL。

2.3、小說網站關於最新更新的展現及html報文格式

根據老猿分析,約占30%的小說網站關於最新更新章節的展現類似如下:

在這裡插入圖片描述

首先有類似“最新章節”或“最新更新”或“最近更新”等類似提示詞,在該提示詞後是顯示最新章節的章節序號及章節名的一個鏈接,對應的報文類似如下:

<p>最新章節:<a href="/book/12/12938/358787.html" rel="external nofollow"  target="_blank">第729章 就是給你們看看的</a></p>

這個報文的特點是:

“最新章節”的文本信息與小說最新章節的鏈接在同一個父標簽內。另外需要說明的是返回的章節url並不是絕對地址,而是小說網站的相對地址。

老猿對搜索小說查找最新章節都是基於以上格式的,因此實際上程序最終獲取的小說網站隻占瞭整個搜索結果的30%左右,不過對於看小說來說已經足夠瞭。

三、實現思路及代碼

3.1、根據url獲取網站名

def getHostName(url):
    httpPost = url[10:]
    hostName = url[:10]+httpPost.split('/')[0]
    return hostName

3.2、根據百度返回搜索結果地址打開網站獲取小說信息

基於2.3部分介紹的小說網站返回內容,我們來根據百度返回搜索結果的URL來打開對應小說網站,並計算從請求發起到響應返回的時間:

def getNoteInfo(url):
    """
    打開指定小說網頁URL獲取最新章節信息
    url:百度搜索結果指定的搜索匹配記錄的url
    返回該URL對應的章節ID、打開耗時、網站真正URL、網站主機名、章節相對url、章節名
    
    """
    head = mkhead()
    start = time.time_ns()
    req = urllib.request.Request(url=url, headers=head)
    try:
        resp = urllib.request.urlopen(req,timeout=2)
        #根據響應頭獲取真正的網頁URL對應的網站名
        hostName = getHostName(resp.url)
        text = resp.read()
        #網頁編碼有2種:utf-8和GBK
        pageText = text.decode('utf-8')
    except UnicodeDecodeError:
        pageText =  text.decode('GBK')
    except Exception as  e:
        errInf = f"打開網站 {url} 失敗,異常原因:\n{e}\n" + '\n' + traceback.format_exc() + '\n'
        logPag(errInf, False)
        return None

    #最新章節的HTML報文類似: '<p>最新章節:<a href="/html/107018/122306672.html" rel="external nofollow" >第672章 天之關梁</a></p>'
    end = time.time_ns()
    soup = BeautifulSoup(pageText, 'lxml')
    # 根據最新章節的提示信息搜索最新章節
    result = soup.find_all(string=re.compile(r'最新更新[::]|最新章節[::]|最近更新[::]|最新[::]'))
    found = False
    for rec in result:
        recP = rec.parent
        pa = recP.a
        matchs = re.match(r'(?:最新更新|最新章節|最近更新|最新)[::]第(.+)章(.+)', recP.text)
        if not matchs:return None
        groups = matchs.groups()
        if matchs and pa is not None:
            found = True
            chapter = toInt(groups[0]) #章節序號
            chapterName = groups[1] #章節名
            chaperUrl = pa.attrs['href'] #章節相對URL
            break
    if not found:
        return None

    cost = (end - start) / 1000000  #網頁打開耗時計算
    return (chapter,cost,resp.url,hostName,chaperUrl,chapterName)

註意:由於不同網站訪問響應情況不一樣,因此在打開網頁時設定超時是很有必要的,這樣可以避免訪問緩慢的網站耽誤整體訪問時間。

3.3、獲取小說網頁絕對url地址

將返回信息中相對url和網站名結合拼湊網頁的絕對url地址:

def getChapterUrl(noteInf):
    chapter, cost, url, hostName, chaperUrl, chapterName = noteInf
    if chaperUrl.strip().startswith('http'):return chaperUrl
    elif chaperUrl.strip().startswith('/'):return hostName.strip()+chaperUrl.strip()
    else:return hostName.strip()+'/'+chaperUrl.strip()

3.4、計算排序權重

根據搜索小說網頁訪問的信息計算排序權重,確保最新章節排在最前,相同章節訪問速度最快網站排在最前。

def noteWeight(n):
#入參n為小說信息元組: chapter, cost, url, hostName, chaperUrl, chapterName
    ch,co = n[:2]
    w = ch * 100000 + min(99999, 100000 / co)
    return w

3.5、進行百度搜索並解析搜索結果訪問小說網站最新更新

根據搜索詞在百度執行搜索,並取最新章節且訪問速度最快的前5個網站url進行輸出:

def BDSearchUsingChrome(inputword,maxCount=150):
    """
    輸出相關搜索結果中具有最新章節且訪問速度最快的前5個網站url
    :param word: 搜索關鍵詞,如小說名、小說名+作者名等
    :param maxCount: 最多處理的搜索記錄數
    :return: None
    """
    #百度請求url類似:https://www.baidu.com/s?wd=青萍&pn=10&rn=50
    rn = 50 #每頁50條記錄
    #構建請求頭模擬本機谷歌瀏覽器訪問百度網頁
    head = mkheadByHostForChrome('baidu.com')
    word =  urllib.parse.quote(inputword)
    urlPagePre = 'https://www.baidu.com/s?wd='+word+'&rn=50&'
    pageCount = int(0.999+maxCount/rn)
    validNoteInf = []
    seq = 0
    logPag("開始執行搜索...")
    for page in range(pageCount):
        pn = rn*page
        urlPage = urlPagePre+str(pn)
        pageReq = urllib.request.Request(url=urlPage, headers=head)
        pageResp = urllib.request.urlopen(pageReq,timeout=2)
        pageText = pageResp.read().decode()

        if pageResp.status == 200:
            soup = BeautifulSoup(pageText,'lxml')
            links = soup.select('h3.t a[href^="http://www.baidu.com/link?url="]')

            for l in links:
                noteInf = getNoteInfo(l.attrs['href'])
                seq += 1
                if noteInf is None:
                    #print(seq,'、',l.attrs['href'],None)
                    logPag(f"{seq}、{l.attrs['href']}:查找最新章節失敗,忽略",True)
                else:
                    logPag(f"{seq}、返回小說信息: {noteInf}",True)
                    #chapter,cost,url,hostName,chaperUrl,chapterName = noteInf
                    validNoteInf.append(noteInf)
    validNoteInf.sort(key=noteWeight,reverse=True)
    print(f"小說: {inputword} 最新更新訪問最快的5個網站是:")
    for l in validNoteInf[:5]:#輸出相關搜索結果中具有最新章節且訪問速度最快的前5個網站url
        print(f"{validNoteInf.index(l)+1}、第{l[0]}章 {l[-1]}  {getChapterUrl(l)}  ,網頁打開耗時 {l[1]} 毫秒")
    input("按回車鍵退出!")

四、搜索案例

以搜索月關大大的青萍作為案例,執行搜索的語句為:

BDSearchUsingChrome('青萍月關',150)

執行結果:

小說: 青萍月關 最新更新訪問最快的5個網站是:
1、第688章  東邊日出西邊雨  http://www.huaxiaci.com/41620/37631250.html  ,網頁打開耗時 262.0 毫秒
2、第688章  東邊日出西邊雨  http://www.huaxiaci.com/41620/37631250.html  ,網頁打開耗時 278.0 毫秒
3、第688章  東邊日出西邊雨  http://www.huaxiaci.com/41620/37631250.html  ,網頁打開耗時 345.5 毫秒
4、第688章  東邊日出西邊雨  https://www.24kwx.com/book/9/9202/8889236.html  ,網頁打開耗時 774.0 毫秒
5、第688章  東邊日出西邊雨  https://www.27kk.net/9526/2658932.html  ,網頁打開耗時 800.5 毫秒
按回車鍵退出!

五、小結

本文介紹瞭使用Python搜索指定小說最新更新章節以及訪問最快網站的實現思想和關鍵應用代碼,實現自動搜索小說最新更新章節以及獲取訪問最快的網站。以上的實現由於已經獲取最新章節的鏈接,再稍微改進,就可以直接將最新章節下載到本地觀看。

到此這篇關於Python爬蟲之爬取最新更新的小說網站的文章就介紹到這瞭,更多相關Python爬取最新更新的小說網站內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: