程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python request模塊(三)—— 正則表達式獲取小說鏈接

編輯:Python

本節是自己改編的用正則表達式抓取數據案例,在第一篇結尾我們留下了兩個問題,學習了第二篇的正則表達式後,我們可以嘗試去解決了。

一、 怎麼獲取目錄中每章的信息

在獲取小說內容之前,我肯定得先從目錄拿到每一章的標題和鏈接

1. 首先確認渲染方式

       也就是要的數據在不在源代碼中。建議多往後翻幾頁看看,有些網頁源碼只是有第一頁的數據,後面的就沒有了(例如csdn)。如果是客戶端渲染,就不能用正則表達式來取。

 這裡我看了幾頁,數據都是在源碼中的,那就比較簡單了。

2. 拿到網頁源碼

首先寫個最簡單的print,獲取網頁信息,方便起見headers參數一並加上。

import requests
url= "https://m.gdedu.tv/dir/73358/?page=1&sort=asc"
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"}
resp = requests.get(url=url,headers=headers)
print(resp.text)
resp.close()

3. 正則匹配想要的信息

我們要標題、鏈接

      隨便點進去一章你會發現,上面herf的鏈接只是一部分,還要再拼上網站首頁的地址 https://m.gdedu.tv

匹配思路如下:

  • 首先復制一行包含所需內容的html出來,看看需要的信息在哪裡

                <li class="ptm-list-view-cell">

                    <a href="/73358/tc_729773.html">章節目錄</a>

                </li>

                <li class="ptm-list-view-cell">

                    <a href="/73358/tc_729774.html">一只小肥啾01</a>

                </li>

       簡單是很簡單,但你會發現不好把“章節目錄”跟真正的章節區分開,不過也沒關系,返回數據的時候再處理就可以。

  • 找到之後開始寫正則表達式

注意:從起始字符串開始,每個值可能會有變化的地方都要匹配到

  1. <a href=" 這段只在我們需要的內容部分出現,因此從它開始
  2. 因為這個鏈接特別簡單,我們直接替換並保存值即可

<a href="/73358/tc_729774.html">一只小肥啾01</a>

obj = re.compile(r'<a href="(?P<link>.*?)">(?P<title>.*?)<',re.S)

  • 取出匹配之後的數據

it = obj.finditer(html)

for i in it:

    print(i.group("title")+'---'+i.group("link"))

跑一下試試:

發現雖然取到了,但有些多余的數據,其實是翻頁的鏈接。

這裡我們還是用標准的傳參方式翻頁,所以在輸出數據的時候過濾掉這些多余的。

it = obj.finditer(html)

for i in it:

    if ("章節目錄" in i.group("title")) or ("Sitemap" in i.group("title")) or ("page" in i.group("link")):

        pass

    else:

        print(i.group("title")+'---'+i.group("link"))

ok~

4. 獲取所有頁

F12抓包,刷新頁面,可以看到它有兩個入參

       但是這裡沒找到有總記錄數的數據,如果想要自動判斷一共多少頁的話,可能還是把上面page鏈接存起來會簡單點?

        這裡我人工看了下,一共4頁,所以有幾個地方要改:

  • 改url地址,去掉?之後的部分
  • 加一個page變量,循環賦值
  • 加一個入參字典
  • get方法加params參數
  • 把link跟前面的root_page拼起來

url= "https://m.gdedu.tv/dir/73358/"

    for page in range(1,5):
        params = {
        "page": page,
        "sort": "asc"
        }
     
        resp = requests.get(url=url,headers=headers,params=params)
        ...
        dic["link"] = root_page+i.group("link")

測試點擊,可以打開

這兩個變量既然取到了,後面保存到文檔也好,保存到list做後續處理也好,就都OK了。

二、 怎麼獲取每章的子頁面鏈接

如果用的是一頁顯示本章全部內容的網站,其實上面的步驟就ok了,不需要這裡。

1. 頁面分析

隨便打開一章,會發現每章裡面也是有分頁的,並且這個頁碼不像目錄的頁碼,抓包裡是沒有的。

但是很明顯這個頁數就在鏈接裡了,這種情況要怎麼判斷每章有多少頁,下頁鏈接是什麼呢?

其實同理,這個“下一章”也有自己對應的鏈接

查看源碼,搜729776,這玩意在JavaScript標簽裡。但是沒關系,只要你會匹配上面的超鏈接,你自然就會匹配下面這個。

2. 匹配下一章鏈接

這個原理跟拿每章鏈接是一樣的,傳入url,然後通過正則表達式匹配鏈接,再拼起來。

# 傳入每章鏈接,獲取本章的子鏈接
def get_next_url(chapter_url,headers):
# chapter_url = "https://m.gdedu.tv/73358/tc_818487.html"
resp = requests.get(url=chapter_url, headers=headers)
# 獲取各章源碼
html = resp.text
# 匹配下一頁鏈接
obj = re.compile(r'var nexturl = "(?P<nexturl>.*?)"', re.S) # re.S 使.也能匹配換行符
# 因為只會有一個nexturl,這裡用search就可以
s = obj.search(html)
# 拼好的下一頁鏈接
full_nexturl = root_page+s.group("nexturl")
return full_nexturl

3. 怎麼確定每章有幾個子頁面?

       下面這個方法是我自己想的,比較直接,如果有更好的方法歡迎指教。

       上面那個函數不難,但它只能拿到一個url的下一頁,肯定得循環調用。但是我要怎麼判斷每章有幾個子頁面?這個不像是目錄頁數看一眼就知道,需要再觀察下頁面源碼。

       找到章節最後一頁,看nexturl有什麼特點:var nexturl = "/73358/tc_818488.html"; (下一章鏈接)

        最大的區別在於下一章的時候tc_後面的數字會+1,而不再是xxx_3,xxx_4 這種子頁面。

        所以我們可以把當前鏈接的818487截取出來,再轉成int類型

# 例如 tc_818487.html 截出來是 818487
cur_id = int(chapter_url["link"].split("_")[1].split(".")[0])

然後還要截一個下一頁id
next_id = int(next_url.split("_")[1].split(".")[0])

代碼如下:

if __name__ == '__main__':

    chapter_url_list = get_chapter_url()

    cnt = 0

    for chapter_url in chapter_url_list:

        f = open("url_list.txt", 'a', encoding='utf-8')

        if cnt == 0:

            # print(chapter_url["link"])

            f.write(chapter_url["link"]+'\n')

            cnt = cnt+1

        # 例如 tc_818487.html 截出來是 818487

        cur_id = int(chapter_url["link"].split("_")[1].split(".")[0])

        next_url = chapter_url["link"]

        # 由於不知道每章子頁面一共有多少,這裡來個死循環

        while True:

            # 獲取下頁鏈接

            next_url = get_next_url(next_url, headers=headers,)

            #print(next_url)

            f.write(next_url+'\n')

            # 如果next_id已經是下一章id(cur_id+1),說明這已經是本章最後一頁,此時跳出while循環

            next_id = int(next_url.split("_")[1].split(".")[0])

            if next_id == cur_id+1:

                break;

        f.close()

       這裡加個計數器(綠色部分)是為了打印第一章第一頁的信息,如果不加的話每章第一頁會重復打印出來,去掉這行輸出的話又會少一章。

4. 將鏈接寫入文件

       主要原因是這個匹配量太大了,每次重新匹配效率會很低,所以直接保存起來。上面代碼藍色部分就是,這裡不重復寫了。

三、 完整代碼及運行結果

運行結果如下:

每一個章節和子頁面的目錄拿到手之後,下一節就可以獲取小說內容了。

完整代碼如下

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2022-06-12 15:17
# @Author: Hehuyi_In
# @File : get_url.py
import requests
import re
# 網站首頁url,用來拼章節鏈接
root_page = "https://m.gdedu.tv"
url= "https://m.gdedu.tv/dir/73358/"
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"}
# 傳入每章鏈接,獲取本章的子鏈接
def get_next_url(chapter_url,headers):
# chapter_url = "https://m.gdedu.tv/73358/tc_818487.html"
resp = requests.get(url=chapter_url, headers=headers)
# 獲取各章源碼
html = resp.text
# 匹配下一頁鏈接
obj = re.compile(r'var nexturl = "(?P<nexturl>.*?)"', re.S) # re.S 使.也能匹配換行符
# 因為只會有一個nexturl,這裡用search就可以
s = obj.search(html)
# 拼好的下一頁鏈接
full_nexturl = root_page+s.group("nexturl")
return full_nexturl
def get_chapter_url():
chapter_url_list=[]
for page in range(1,5):
params = {
"page": page,
"sort": "asc"
}
resp = requests.get(url=url,headers=headers,params=params)
# 網頁源碼
html = resp.text
# 匹配各章節鏈接
obj = re.compile(r'<a href="(?P<link>.*?)">(?P<title>.*?)<',re.S) # re.S 使.也能匹配換行符
it = obj.finditer(html)
for i in it:
if ("章節目錄" in i.group("title")) or ("Sitemap" in i.group("title")) or ("page" in i.group("link")):
pass
else:
dic={}
dic["title"]=i.group("title")
dic["link"] = root_page+i.group("link")
chapter_url_list.append(dic)
resp.close()
return chapter_url_list
if __name__ == '__main__':
chapter_url_list = get_chapter_url()
cnt = 0
for chapter_url in chapter_url_list:
f = open("url_list.txt", 'a', encoding='utf-8')
if cnt == 0:
# print(chapter_url["link"])
f.write(chapter_url["link"]+'\n')
cnt = cnt+1
# 例如 tc_818487.html 截出來是 818487
cur_id = int(chapter_url["link"].split("_")[1].split(".")[0])
next_url = chapter_url["link"]
# 由於不知道每章子頁面一共有多少,這裡來個死循環
while True:
# 獲取下頁鏈接
next_url = get_next_url(next_url, headers=headers,)
#print(next_url)
f.write(next_url+'\n')
# 找到章節最後一頁,看有什麼特點:var nexturl = "/73358/tc_818488.html"; (下一章鏈接)
# 如果next_id已經是下一章id(cur_id+1),說明這已經是本章最後一頁,此時跳出while循環
next_id = int(next_url.split("_")[1].split(".")[0])
if next_id == cur_id+1:
break;
f.close()

參考:B站視頻 P23-P27

2021年最新Python爬蟲教程+實戰項目案例(最新錄制)_哔哩哔哩_bilibili


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved