Python用正則表達式實現爬取古詩文網站信息

分析古詩文網站

下圖1展示瞭古詩文網站—》詩文 欄目的首頁數據。該欄目的地址是:https://so.gushiwen.cn/shiwens/

第二頁的地址是:https://so.gushiwen.cn/shiwens/default.aspx?page=2&tstr=&astr=&cstr=&xstr= 。依次類推第n頁的地址就是page=n。其他不變。

1. 用正則表達式獲取總頁數

匹配的正則表達式是r'<div class=”pagesright”>.*?<span .*?>(.*?)</span>’

  1. 首先,r修飾的字符串是原生字符串,首先匹配到<div class=”pagesright”> 標簽,然後再通過.*?匹配到裡面的裡面的<a>標簽<span>標簽等。這裡. 可以匹配到任意的一個字符(換行符除外),* 號可以匹配0或者任意多個字符。? 號表示隻能匹配到1個或者0個。這裡加上?號是為瞭使用非貪婪模式。
  2. <span .*?> 通過匹配到存放總頁數的<span>標簽。在標簽裡指定.*?
  3. (.*?) 加上() 可以指定不同的分組,這裡我們隻需要獲取頁數所以就單獨添加一個分組。

所以,最終的代碼是:

 def get_total_pages():
    resp = requests.get(first_url)
    # 獲取總頁數
    ret = re.findall(r'<div class="pagesright">.*?<span .*?>(.*?)</span>', resp.text, re.DOTALL)
    result = re.search('\d+', ret[0])
    for page_num in range(int(result.group())):
        url = 'https://so.gushiwen.cn/shiwens/default.aspx?page=' + str(page_num)
        parse_page(url)

在findall方法中傳入re.DOTALL參數是為瞭是. 號可以匹配到換行符\n。

前面ret的結果是/ 5頁。再獲取5這個數字的話,還需要做一次匹配查找,這就是通過re.search(‘\d+’, ret[0]) 來進行查找。

2. 提取詩的標題

如上圖2展示瞭詩的標題的HTML源碼,從中可以看出詩的標題被存在<b>標簽 匹配詩的標題的正則表達式是<div class=”cont”>.*?<b>(.*?)</b>

首先還是匹配到<div class=”cont”> 標簽,接著就是匹配<b>(.*?)</b> 這裡還是采用非貪婪模式來進行匹配。

3. 提取作者和朝代

如上圖3展示瞭詩的作者和朝代的HTML源碼,從中可以看出作者和朝代都是在<p class=”source”></p> 標簽下的兩個a標簽中。

3.1 提取作者

提取作者的正則表達式是<p class=”source”>.*?<a .*?>(.*?)</a> 首先還是匹配到<p class=”source”> 標簽。接著就是匹配第一個<a> 標簽中的內容。

3.2 提取朝代

提取朝代的正則表達式是<p class=”source”>.*?<a .*?><a .*?>(.*?)</a> 與提取作者不同的是多瞭一個<a .*?> ,這是因為朝代在第二個<a>標簽中。

4. 提取詩的內容

如上圖4展示瞭詩的內容的HTML源碼,從中可以看出詩句都在<div class=”contson”>標簽中,所以隻需要匹配到這個標簽裡的內容即可。其正則表達式是<div class=”contson” .*?>(.*?)</div>。

但是這樣匹配出來的數據是包含<br> 標簽的。所以,我們需要通過sub 方法將這個標簽替換掉。re.sub(r'<.*?>+’, “”, content)。

整理代碼

至此,我們就將所有想要的數據都提取到瞭。接下來,我們還需要對數據進行處理。我們期望的最終數據格式是:

 poems=[
        {
            "title": '漁傢傲·花底忽聞敲兩槳',
            "author":'張三',
            'dynasty':'唐朝',
            'content':'xxxxxx'
        }
          {
            "title": '鵝鵝鵝',
            "author":'李四',
            'dynasty':'唐朝',
            'content':'xxxxxx'
        }
    ]

前面,我們分別得到瞭所有標題的列表titles;所有作者的列表authors;所有朝代的列表dynastys;所有詩句的列表contents。

那麼,我們如何將這些列表組合成上面的那種形式呢?

這裡,就需要用到 zip 函數瞭。該函數可以將多個列表組合成一個新的列表,其中列表的元素是元組。比如:

a=['name','age']
b=['張三',18]
c=zip(a,b)

調用zip 方法之後得到一個zip對象,該對象可以轉換成list 對象。最終得到的結果如下圖5

完整源代碼

# -*- utf-8 -*-
"""
@url: https://blog.csdn.net/u014534808
@Author: 碼農飛哥
@File: gushiwen_rep.py
@Time: 2021/12/7 07:40
@Desc: 用正則表達式爬取古詩文網站
古詩文網站的地址:
https://www.gushiwen.cn/
"""
import re
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36'
}

first_url = 'https://so.gushiwen.cn/shiwens/default.aspx'


def get_total_pages():
    resp = requests.get(first_url)
    # 獲取總頁數
    ret = re.findall(r'<div class="pagesright">.*?<span .*?>(.*?)</span>', resp.text, re.DOTALL)
    result = re.search('\d+', ret[0])
    for page_num in range(int(result.group())):
        url = 'https://so.gushiwen.cn/shiwens/default.aspx?page=' + str(page_num)
        parse_page(url)


# 解析頁面
def parse_page(url):
    resp = requests.get(url)
    text = resp.text
    # 提取標題 (.*) 進行分組,隻提取<b>標簽中的內容,默認情況下 .不能匹配\n。加上re.DOTALL 表示.號可以匹配所有,貪婪模式
    # titles = re.findall(r'<div class="cont">.*<b>(.*)</b>', text,re.DOTALL)
    # 非貪婪模式
    titles = re.findall(r'<div class="cont">.*?<b>(.*?)</b>', text, re.DOTALL)
    # 提取作者
    authors = re.findall(r'<p class="source">.*?<a .*?>(.*?)</a>', text, re.DOTALL)
    # 提取朝代
    dynastys = re.findall(r'<p class="source">.*?<a .*?><a .*?>(.*?)</a>', text, re.DOTALL)
    # 提取詩句
    content_tags = re.findall(r'<div class="contson" .*?>(.*?)</div>', text, re.DOTALL)
    contents = []
    for content in content_tags:
        content = re.sub(r'<.*?>+', "", content)
        contents.append(content)
    poems = []

    for value in zip(titles, authors, dynastys, contents):
        # 解包
        title, author, dynasty, content = value
        poems.append(
            {
                "title": title,
                "author": author,
                'dynasty': dynasty,
                'content': content
            }
        )
    print(poems)
    """
    poems=[
        {
            "title": '漁傢傲·花底忽聞敲兩槳',
            "author":'張三',
            'dynasty':'唐朝',
            'content':'xxxxxx'
        }
          {
            "title": '漁傢傲·花底忽聞敲兩槳',
            "author":'張三',
            'dynasty':'唐朝',
            'content':'xxxxxx'
        }
    ]
    """


"""
zip 函數
a=['name','age']
b=['張三',18]
c=zip(a,b)
c=[
    ('name','張三'),
    ('age',18)
]
"""

if __name__ == '__main__':
    get_total_pages()

最終的運行結果是:

總結

本文以古詩文網為例演示瞭如何通過正則表達式來爬取網站數據。 

以上就是Python用正則表達式實現爬取古詩文網站信息的詳細內容,更多關於Python正則表達式爬取網站信息的資料請關註WalkonNet其它相關文章!

推薦閱讀: