python帶你一步步從單章小說(shuō)下載到GUI界面制作

嗨嘍,大家好呀~這里是愛(ài)看美女的茜茜吶

環(huán)境使用:

  • Python 3.10 解釋器

  • Pycharm 編輯器

模塊使用

  • import requests --> 數(shù)據(jù)請(qǐng)求模塊 第三方模塊, 需要安裝

  • import re --> 正則表達(dá)式模塊 內(nèi)置模塊, 不需要安裝

  • import parsel --> 數(shù)據(jù)解析模塊 第三方模塊, 需要安裝

  • import os --> 文件操作模塊 內(nèi)置模塊, 不需要安裝

  • import concurrent.futures --> 線程池

如何安裝python第三方模塊:

  1. win + R 輸入 cmd 點(diǎn)擊確定, 輸入安裝命令 pip install 模塊名 (pip install requests) 回車

  2. 在pycharm中點(diǎn)擊Terminal(終端) 輸入安裝命令

爬蟲(chóng)基本實(shí)現(xiàn)思路

一. 數(shù)據(jù)來(lái)源分析

  1. 明確需求:

  2. 分析 標(biāo)題/內(nèi)容 是從哪里來(lái)的

    通過(guò)瀏覽器自帶工具: 開(kāi)發(fā)者工具抓包分析

    • 打開(kāi)開(kāi)發(fā)者工具: F12 / 鼠標(biāo)右鍵點(diǎn)擊檢查選擇network

    • 刷新網(wǎng)頁(yè)

    • 搜索數(shù)據(jù), 找到數(shù)據(jù)包

      https://www.biqudu.net/1_1631/3047505.html

二. 代碼實(shí)現(xiàn)步驟:

  1. 發(fā)送請(qǐng)求, 模擬瀏覽器對(duì)于url地址發(fā)送請(qǐng)求

    請(qǐng)求鏈接: https://www.biqudu.net/1_1631/3047505.html

  2. 獲取數(shù)據(jù), 獲取服務(wù)器返回響應(yīng)數(shù)據(jù)內(nèi)容

    開(kāi)發(fā)者工具: response

  3. 解析數(shù)據(jù), 提取我們想要的數(shù)據(jù)內(nèi)容

    標(biāo)題/內(nèi)容

  4. 保存數(shù)據(jù), 把數(shù)據(jù)保存本地文件

單章小說(shuō)下載

導(dǎo)入模塊

import requests
import re
import parsel

"""

  1. 發(fā)送請(qǐng)求, 模擬瀏覽器對(duì)于url地址發(fā)送請(qǐng)求

    請(qǐng)求鏈接: https://www.biqudu.net/1_1631/3047505.html

    安裝模塊方法:

    • win + R 輸入cmd, 輸入安裝命令 pip install requests

    • 在pycharm終端, 輸入安裝命令

    模擬瀏覽器 headers 請(qǐng)求頭:

     字典數(shù)據(jù)結(jié)構(gòu)
    

    AttributeError: 'set' object has no attribute 'items'

     因?yàn)閔eaders不是字典數(shù)據(jù)類型, 而是set集合
    

"""

請(qǐng)求鏈接

url = 'https://www.biqudu.net/1_1631/3047505.html'

模擬瀏覽器 headers 請(qǐng)求頭

headers = {
    # user-agent 用戶代理 表示瀏覽器基本身份信息
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
}

發(fā)送請(qǐng)求

response = requests.get(url=url, headers=headers)

<Response [200]> 響應(yīng)對(duì)象, 表示請(qǐng)求成功

print(response)

"""

  1. 獲取數(shù)據(jù), 獲取服務(wù)器返回響應(yīng)數(shù)據(jù)內(nèi)容

    開(kāi)發(fā)者工具: response

    response.text --> 獲取響應(yīng)文本數(shù)據(jù) <網(wǎng)頁(yè)源代碼/html字符串?dāng)?shù)據(jù)>

  2. 解析數(shù)據(jù), 提取我們想要的數(shù)據(jù)內(nèi)容

    標(biāo)題/內(nèi)容

"""
獲取下來(lái)response.text <html字符串?dāng)?shù)據(jù)>, 轉(zhuǎn)成可解析對(duì)象

selector = parsel.Selector(response.text)
# 提取標(biāo)題
title = selector.xpath('//*[@class="bookname"]/h1/text()').get()
# 提取內(nèi)容
content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())
print(title)
print(content)

"""

  1. 保存數(shù)據(jù), 把數(shù)據(jù)保存本地文件

"""

title <文件名> '.txt' 文件格式 a 追加保存 encoding 編碼格式 as 重命名

with open(title + '.txt', mode='a', encoding='utf-8') as f:
    """
    第一章 標(biāo)題
        小說(shuō)內(nèi)容
    第二章 標(biāo)題
        小說(shuō)內(nèi)容
    """

寫(xiě)入內(nèi)容

    f.write(title)
    f.write('\n')
    f.write(content)
    f.write('\n')

小知識(shí)點(diǎn)

  • re正則表達(dá)式: 是直接對(duì)于字符串?dāng)?shù)據(jù)進(jìn)行解析

    re.findall('什么數(shù)據(jù)', '什么地方') --> 從什么地方, 去找什么數(shù)據(jù)

    .*? --> 可以匹配任意數(shù)據(jù), 除了\n換行符

     # 提取標(biāo)題
     title = re.findall('<h1>(.*?)</h1>', response.text)[0]
     # 提取內(nèi)容
     content = re.findall('<div id="content">(.*?)<p>', response.text, re.S)[0].replace('<br/><br/>', '\n')
    
  • css選擇器: 根據(jù)標(biāo)簽屬性提取數(shù)據(jù)

    .bookname h1::text

    類名為bookname下面h1標(biāo)簽里面文本

    get() --> 提取第一個(gè)標(biāo)簽數(shù)據(jù)內(nèi)容 返回字符串

    getall() --> 提取多個(gè)數(shù)據(jù), 返回列表

     # 提取標(biāo)題
     title = selector.css('.bookname h1::text').get()
     # 提取內(nèi)容
     content = '\n'.join(selector.css('#content::text').getall())
    
  • xpath節(jié)點(diǎn)提取: 提取標(biāo)簽節(jié)點(diǎn)提取數(shù)據(jù)

整本小說(shuō)下載

import requests
import re
import parsel
import os

# 請(qǐng)求鏈接: 小說(shuō)目錄頁(yè)
list_url = 'https://www.biqudu.net/1_1631/'
# 模擬瀏覽器 headers 請(qǐng)求頭
headers = {
    # user-agent 用戶代理 表示瀏覽器基本身份信息
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
}
# 發(fā)送請(qǐng)求
html_data = requests.get(url=list_url, headers=headers).text
# 提取小說(shuō)名字
name = re.findall('<h1>(.*?)</h1>', html_data)[0]
# 自動(dòng)創(chuàng)建一個(gè)文件夾
file = f'{name}\\'
if not os.path.exists(file):
    os.mkdir(file)

# 提取章節(jié)url
url_list = re.findall('<dd> <a style="" href="(.*?)">', html_data)
# for循環(huán)遍歷
for url in url_list:
    index_url = 'https://www.biqudu.net' + url
    print(index_url)
    # # 請(qǐng)求鏈接
    # url = 'https://www.biqudu.net/1_1631/3047506.html'
    # 模擬瀏覽器 headers 請(qǐng)求頭
    headers = {
        # user-agent 用戶代理 表示瀏覽器基本身份信息
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
    }
    # 發(fā)送請(qǐng)求
    response = requests.get(url=index_url, headers=headers)
    # <Response [200]> 響應(yīng)對(duì)象, 表示請(qǐng)求成功
    print(response)
    # 獲取下來(lái)response.text <html字符串?dāng)?shù)據(jù)>, 轉(zhuǎn)成可解析對(duì)象
    selector = parsel.Selector(response.text)
    # 提取標(biāo)題
    title = selector.xpath('//*[@class="bookname"]/h1/text()').get()
    # 提取內(nèi)容
    content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())
    print(title)
    # print(content)
    # title <文件名> '.txt' 文件格式  a 追加保存 encoding 編碼格式 as 重命名
    with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
        f.write(title)
        f.write('\n')
        f.write(content)
        f.write('\n')

多線程采集小說(shuō)

導(dǎo)入模塊

import requests
import re
import parsel
import os
import concurrent.futures
def get_response(html_url):
    """
    發(fā)送請(qǐng)求函數(shù)
    :param html_url: 請(qǐng)求鏈接
    :return: response響應(yīng)對(duì)象
    """
    # 模擬瀏覽器 headers 請(qǐng)求頭
    headers = {
        # user-agent 用戶代理 表示瀏覽器基本身份信息
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
    }
    response = requests.get(url=html_url, headers=headers)
    return response
def get_list_url(html_url):
    """
    獲取章節(jié)url/小說(shuō)名
    :param html_url: 小說(shuō)目錄頁(yè)
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取小說(shuō)名字
    name = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取章節(jié)url
    url_list = re.findall('<dd> <a style="" href="(.*?)">', html_data)
    return name, url_list
def get_content(html_url):
    """
    獲取小說(shuō)內(nèi)容/小說(shuō)標(biāo)題
    :param html_url: 小說(shuō)章節(jié)url
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取標(biāo)題
    title = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取內(nèi)容
    content = re.findall('<div id="content">(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
    return title, content
def save(name, title, content):
    """
    保存數(shù)據(jù)函數(shù)
    :param name: 小說(shuō)名
    :param title: 章節(jié)名
    :param content: 內(nèi)容
    :return:
    """
    # 自動(dòng)創(chuàng)建一個(gè)文件夾
    file = f'{name}\\'
    if not os.path.exists(file):
        os.mkdir(file)
    with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
        """
        第一章 標(biāo)題
            小說(shuō)內(nèi)容
        第二章 標(biāo)題
            小說(shuō)內(nèi)容
        """
        # 寫(xiě)入內(nèi)容
        f.write(title)
        f.write('\n')
        f.write(content)
        f.write('\n')
    print(title, '已經(jīng)保存')


def main(home_url):
    # index_url = 'https://www.biqudu.net' + url
    title, content = get_content(html_url=home_url)
    save(name, title, content)


if __name__ == '__main__':
    url = 'https://www.biqudu.net/1_1631/'
    name, url_list = get_list_url(html_url=url)
    exe = concurrent.futures.ThreadPoolExecutor(max_workers=7)
    for url in url_list:
        index_url = 'https://www.biqudu.net' + url
        exe.submit(main, index_url)
    exe.shutdown()

下載排行所有小說(shuō)

import requests
import re
import parsel
import os

def get_response(html_url):
    """
    發(fā)送請(qǐng)求函數(shù)
    :param html_url: 請(qǐng)求鏈接
    :return: response響應(yīng)對(duì)象
    """
    # 模擬瀏覽器 headers 請(qǐng)求頭
    headers = {
        # user-agent 用戶代理 表示瀏覽器基本身份信息
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
    }
    response = requests.get(url=html_url, headers=headers)
    return response

def get_list_url(html_url):
    """
    獲取章節(jié)url/小說(shuō)名
    :param html_url: 小說(shuō)目錄頁(yè)
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取小說(shuō)名字
    name = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取章節(jié)url
    url_list = re.findall('<dd> <a style="" href="(.*?)">', html_data)
    return name, url_list

def get_content(html_url):
    """
    獲取小說(shuō)內(nèi)容/小說(shuō)標(biāo)題
    :param html_url: 小說(shuō)章節(jié)url
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取標(biāo)題
    title = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取內(nèi)容
    content = re.findall('<div id="content">(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
    return title, content

def save(name, title, content):
    """
    保存數(shù)據(jù)函數(shù)
    :param name: 小說(shuō)名
    :param title: 章節(jié)名
    :param content: 內(nèi)容
    :return:
    """
    # 自動(dòng)創(chuàng)建一個(gè)文件夾
    file = f'{name}\\'
    if not os.path.exists(file):
        os.mkdir(file)
    with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
        """
        第一章 標(biāo)題
            小說(shuō)內(nèi)容
        第二章 標(biāo)題
            小說(shuō)內(nèi)容
        """
        # 寫(xiě)入內(nèi)容
        f.write(title)
        f.write('\n')
        f.write(content)
        f.write('\n')
    print(title, '已經(jīng)保存')

def get_novel_id(html_url):
    """
    獲取小說(shuō)ID
    :param html_url: 某分類的鏈接
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    novel_data = get_response(html_url=html_url).text
    selector = parsel.Selector(novel_data)
    href = selector.css('.l .s2 a::attr(href)').getall()
    href = [i.replace('/', '') for i in href]
    return href


def main(home_url):
    href = get_novel_id(html_url=home_url)
    for novel_id in href:
        novel_url = f'https://www.biqudu.net/{novel_id}/'
        name, url_list = get_list_url(html_url=novel_url)
        print(name, url_list)
        for url in url_list:
            index_url = 'https://www.biqudu.net' + url
            title, content = get_content(html_url=index_url)
            save(name, title, content)
        break


if __name__ == '__main__':
    html_url = 'https://www.biqudu.net/biquge_1/'
    main(html_url)

小說(shuō)搜搜功能

# 導(dǎo)入數(shù)據(jù)請(qǐng)求模塊 --> 第三方模塊, 需要安裝
import requests
# 導(dǎo)入正則表達(dá)式模塊 --> 內(nèi)置模塊, 不需要安裝
import re
# 導(dǎo)入數(shù)據(jù)解析模塊 --> 第三方模塊, 需要安裝
import parsel
# 導(dǎo)入文件操作模塊 --> 內(nèi)置模塊, 不需要安裝
import os
# 導(dǎo)入漂亮的表格
import prettytable as pt


def get_response(html_url):
    """
    發(fā)送請(qǐng)求函數(shù)
    :param html_url: 請(qǐng)求鏈接
    :return: response響應(yīng)對(duì)象
    """
    # 模擬瀏覽器 headers 請(qǐng)求頭
    headers = {
        # user-agent 用戶代理 表示瀏覽器基本身份信息
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
    }
    response = requests.get(url=html_url, headers=headers)
    return response


def get_list_url(html_url):
    """
    獲取章節(jié)url/小說(shuō)名
    :param html_url: 小說(shuō)目錄頁(yè)
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取小說(shuō)名字
    name = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取章節(jié)url
    url_list = re.findall('<dd> <a style="" href="(.*?)">', html_data)
    return name, url_list

def get_content(html_url):
    """
    獲取小說(shuō)內(nèi)容/小說(shuō)標(biāo)題
    :param html_url: 小說(shuō)章節(jié)url
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    html_data = get_response(html_url).text
    # 提取標(biāo)題
    title = re.findall('<h1>(.*?)</h1>', html_data)[0]
    # 提取內(nèi)容
    content = re.findall('<div id="content">(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
    return title, content


def save(name, title, content):
    """
    保存數(shù)據(jù)函數(shù)
    :param name: 小說(shuō)名
    :param title: 章節(jié)名
    :param content: 內(nèi)容
    :return:
    """
    # 自動(dòng)創(chuàng)建一個(gè)文件夾
    file = f'{name}\\'
    if not os.path.exists(file):
        os.mkdir(file)
    with open(file + name + '.txt', mode='a', encoding='utf-8') as f:
        """
        第一章 標(biāo)題
            小說(shuō)內(nèi)容
        第二章 標(biāo)題
            小說(shuō)內(nèi)容
        """
        # 寫(xiě)入內(nèi)容
        f.write(title)
        f.write('\n')
        f.write(content)
        f.write('\n')
    print(title, '已經(jīng)保存')


def get_novel_id(html_url):
    """
    獲取小說(shuō)ID
    :param html_url: 某分類的鏈接
    :return:
    """
    # 調(diào)用發(fā)送請(qǐng)求函數(shù)
    novel_data = get_response(html_url=html_url).text
    selector = parsel.Selector(novel_data)
    href = selector.css('.l .s2 a::attr(href)').getall()
    href = [i.replace('/', '') for i in href]
    return href


def search(word):
    """
    搜索功能
    :param word: 書(shū)名/作者
    :return:
    """
    search_url = f'https://www.biqudu.net/searchbook.php?keyword={word}'
    # 發(fā)送請(qǐng)求
    search_data = get_response(html_url=search_url).text
    # 解析數(shù)據(jù), 提取小說(shuō)名字/作者/小說(shuō)ID
    selector = parsel.Selector(search_data)
    lis = selector.css('.novelslist2 li')
    novel_info = []
    tb = pt.PrettyTable()
    tb.field_names = ['序號(hào)', '書(shū)名', '作者', '書(shū)ID']
    num = 0
    for li in lis[1:]:
        # 小說(shuō)名字
        name = li.css('.s2 a::text').get()
        novel_id = li.css('.s2 a::attr(href)').get().replace('/', '')
        writer = li.css('.s4::text').get()
        dit = {
            'name': name,
            'writer': writer,
            'novel_id': novel_id,
        }
        tb.add_row([num, name, writer, novel_id])
        num += 1
        novel_info.append(dit)
    print('你搜索的結(jié)果如下:')
    print(tb)
    novel_num = input('請(qǐng)輸入你想要下載的小說(shuō)序號(hào): ')
    novel_id = novel_info[int(novel_num)]['novel_id']
    return novel_id


def main(word):
    """
    主函數(shù)
    """
    novel_id = search(word)
    novel_url = f'https://www.biqudu.net/{novel_id}/'
    name, url_list = get_list_url(html_url=novel_url)
    print(name, url_list)
    for url in url_list:
        index_url = 'https://www.biqudu.net' + url
        title, content = get_content(html_url=index_url)
        save(name, title, content)



if __name__ == '__main__':
    word = input('請(qǐng)輸入你搜索小說(shuō)名: ')
    main(word)

制作GUI界面

導(dǎo)入模塊

import tkinter as tk
from tkinter import ttk
def show():
    name = name_va.get()
    print('輸入的名字是:', name)

def download():
    name = num_va.get()
    print('輸入的序號(hào):', name)

創(chuàng)建界面

root = tk.Tk()

設(shè)置標(biāo)題

root.title('小說(shuō)下載器')

設(shè)置界面大小

root.geometry('500x500+200+200')

設(shè)置可變變量

name_va = tk.StringVar()

設(shè)置標(biāo)簽

search_frame = tk.Frame(root)
search_frame.pack(pady=10)

設(shè)置文本

tk.Label(search_frame, text='書(shū)名 作者', font=('微軟雅黑', 15)).pack(side=tk.LEFT, padx=10)

設(shè)置輸入框

tk.Entry(search_frame, relief='flat', textvariable=name_va).pack(side=tk.LEFT)

序號(hào)獲取

num_va = tk.StringVar()

查詢下載輸入框

download_frame = tk.Frame(root)
download_frame.pack(pady=10)

設(shè)置文本

tk.Label(download_frame, text='小說(shuō) 序號(hào)', font=('微軟雅黑', 15)).pack(side=tk.LEFT, padx=10)

設(shè)置輸入框

tk.Entry(download_frame, relief='flat', textvariable=num_va).pack(side=tk.LEFT)

按鈕設(shè)置

button_frame = tk.Frame(root)
button_frame.pack(pady=10)

設(shè)置查詢按鈕

tk.Button(button_frame, text='查詢', font=('微軟雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=show).pack(side=tk.LEFT, padx=10)

設(shè)置下載按鈕

tk.Button(button_frame, text='下載', font=('微軟雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=download).pack(side=tk.LEFT, padx=10)

提前設(shè)置標(biāo)簽名字和中文顯示內(nèi)容

columns = ('num', 'writer', 'name', 'novel_id')
columns_value = ('序號(hào)', '作者', '書(shū)名', '書(shū)ID')
tree_view = ttk.Treeview(root, height=18, show='headings', columns=columns)

設(shè)置列名

tree_view.column('num', width=40, anchor='center')
tree_view.column('writer', width=40, anchor='center')
tree_view.column('name', width=40, anchor='center')
tree_view.column('novel_id', width=40, anchor='center')

給列名設(shè)置顯示的名字

tree_view.heading('num', text='序號(hào)')
tree_view.heading('writer', text='作者')
tree_view.heading('name', text='書(shū)名')
tree_view.heading('novel_id', text='書(shū)ID')
tree_view.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

展示界面

root.mainloop()

尾語(yǔ)

感謝你觀看我的文章吶~本次航班到這里就結(jié)束啦 ??

希望本篇文章有對(duì)你帶來(lái)幫助 ??,有學(xué)習(xí)到一點(diǎn)知識(shí)~

躲起來(lái)的星星??也在努力發(fā)光,你也要努力加油(讓我們一起努力叭)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容