python:根據小說名稱爬取電子書


簡介

上一章節小編用python爬取了“斗羅大陸”單本小說,經過周末馬不停蹄、加班加點、抓耳撓腮的搬磚。終於在今天,經過優化處理后,一款基於python爬蟲來爬取千千小說網站的程序出來了,主要功能有以下幾點:

  • 根據需要,輸入想要查看的頁數,查詢頁數內的所有小說。
  • 展示小說ID序號及小說名稱。
  • 輸入小說ID,進行對應的下載。
  • 下載完畢后,進行持久化存儲到文件夾。

下面,開始展示成果吧,哈哈哈哈:

頁數查詢結果顯示

 

 

下載書籍輸入ID及進度展示

 

 

文件夾儲存展示

 

 

第一步,導包

import os
from lxml import etree
from pathlib import Path
from requests import Session

具體使用可以參考上一章《python:爬取“斗羅大陸”電子書》 哦~

第二步,判斷存儲文件夾

def is_exists(book_name):
    """
    判斷存儲路徑是否存在,不存在就新建

    :param book_name: 書籍名稱
    :return:
    """

    base_dir = Path(__file__).parent.joinpath("BOOK")
    if not os.path.exists(base_dir):
        os.mkdir(base_dir)
    return base_dir.joinpath(book_name)

依舊是新建文件……

第三步,封裝一個公共方法

def request_url(url, is_text: bool = False):
    """
    請求url,直接定義的get請求

    :param url:
    :param is_text: 判斷數據是返回解析的數據還是原始的數據
    :return:
    """

    s = Session()

    def encoding_gbk(r):
        """
        轉碼
        :param r:
        :return:
        """
        r.encoding = "gbk"
        return etree.HTML(r.text)

    s.headers.update({
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
    })
    response = s.get(url=url)
    return encoding_gbk(response) if is_text else etree.HTML(response.text)

  • s=Session():可以理解成類似瀏覽器
  • encoding_gbk(r):局部函數看,進行轉碼操作
  • s.headers.update:是更新headers頭
  • return 根據判斷返回轉碼的數據或是已解析的數據

第四步,分析待爬目標處理URL

 

 

看頁面,注意觀察到第一頁的URL為https://www.qqxsw.co/top/allvisit/,當查看第二頁、第三頁…時候的URL時,后面就多了個頁數+.html,例如第二頁的URL值是這樣的https://www.qqxsw.co/top/allvisit/2.html。於是,小編得出這樣的一個想法:URL=https://www.qqxsw.co/top/allvisit/頁數.html

封裝一個函數,開始進行處理.....

def page_num_url(page: int):
    """
    排行榜鏈接
    獲取自定義分頁url列表

    :param page: 頁碼
    :return:
    """
    time_url = "https://www.qqxsw.co/top/allvisit/"
    page_url_list = []
    for num in range(1, page + 1):
        # 拼接分頁地址,並插入列表
        page_url_list.append(time_url + str(num) + ".html")
    return page_url_list

這里也可以改成定義一個起始頁數、一個結束頁數,這樣就更方便查詢了,小伙伴們可以試試哈。

第五步,處理頁數和所有小說的URL

啟用萬能工具F12,指定定位到小說名稱,然后….小編驚喜的看到,可以通過獲取href的屬性值就可以直接獲取完整的小說目錄URL(終於不用拼接了呀),同理,通過title屬性值就能得到小說名稱,nice!!!!

為了能一一對應展示出小說名稱及URL,小編這里把它們存到了字典里,方便后面取….(老實說,但是實現的時候因為不熟練也不太好取),代碼封裝如下:

def article_url_list(page: int):
    """
    獲取完整小說URL列表

    :param page: 頁碼
    :return:
    """
    article_list = []
    for url in page_num_url(page):
        response = request_url(url=url, is_text=True)
        span_list = response.xpath('//div[@class="novelslistss"]/li/span[@class="s2"]')
        # 獲取所有的小說url、名稱
        for span in span_list:
            url_list = span.xpath("./a/@href")
            article_name_list = span.xpath("./a/@title")
            if len(url_list) & len(article_name_list) > 0:
                dic_list = {
                    "url": url_list[0],
                    "name": article_name_list[0]
                }
                article_list.append(dic_list)
    return article_list

第六步,展示之前查詢頁碼的所有的ID及書籍名稱

之前存儲的字典,現在可以用上了…通過遍歷之前字典的索引值及書籍名稱,控制台進行展示。

def show_name(page: int):
    """
    顯示書籍名稱及索引值

    :param page: 頁碼
    :return:
    """
    for i in article_url_list(page):
        # 打印索引編碼和書籍名稱
        print(f"編號:{article_url_list(page).index(i)} - 書籍名稱:{i['name']}")

第七步,指定ID下載,取出小說名稱用於后續調用

def download_url(number: int, page: int):
    """
    指定ID下載,返回具體書籍url

    :param number:
    :param page:
    :return:
    """
    return article_url_list(page)[number]["url"]


def txt_name(number: int, page: int):
    """
    返回書籍名稱

    :param number:
    :param page:
    :return:
    """
    return article_url_list(page)[number]["name"]

第八步,小說下載存儲處理

def download_article(number: int, page: int):
    """
    小說存儲下載處理

    :param number:
    :param page:
    :return:
    """

    def handle_():
        # 封面目錄頁
        response = request_url(url=download_url(number, page))

        # 提取章節url
        url_list = []
        for dd in response.xpath('//div[@id="list"]/dl/dd'):
            detail_url_list = dd.xpath("./a/@href")
            if len(detail_url_list) > 0:
                url_list.append(detail_url_list[0])
        return url_list

    # 處理詳情頁
    with open(is_exists(f"{txt_name(number, page)}.txt"), "w+", encoding="utf-8") as fp:
        # 循環去重,轉回列表並排序的數據
        for page_url in sorted(list(set(handle_()))):
            detail_url = download_url(number, page) + page_url
            response = request_url(url=detail_url, is_text=True)
            detail_name = response.xpath('//div[@class="bookname"]/h1/text()')[0]
            detail_data = response.xpath('//div[@id="content"]/text()')
            # 列表轉字符串,然后持久化存儲數據
            fp.write(detail_name + "\n" + "".join(detail_data) + "\n")

            print(detail_name, "下載成功!!")

    print("全部下載成功!!!!!")

第九步,運行

集合一個入口函數,直接調用運行即可:

def main():
    """
    主運行入口
    :param page:
    :param number:
    :return:
    """
    page = int(input("請輸入要查詢的頁數:"))
    number = int(input("下載的書籍序號:"))
    print("*" * 15, "存在以下可下載書籍", "*" * 15)
    show_name(page)
    print("*" * 42)
    article_url_list(page)
    print(txt_name(number, page), "正在下載,請稍等....")
    download_article(number, page)


if __name__ == '__main__':
    main()

搞定!!!!現在給大家展示一下小編用這個下載器下載的小說吧~

 

 

第十步,總結感悟

小編爬蟲還在提升中,有很多不成熟的地方,在實現整個功能的時候也發現了封裝不當導致代碼凌亂的問題,在這次代碼里有以下2點感覺比較難處理:

  1. 小說名稱與URL的存入和取出,建議打印出來后對照着來調試取值會快很多。
  2. input的使用位置存放的不好,后來經過和小伙伴的談論后進行了重新修改,代碼整體舒服多了。

以上總結或許能幫助到你,或許幫助不到你,但還是希望能幫助到你,如有疑問、歧義,直接私信留言會及時修正發布;非常期待你的點贊和分享喲,謝謝!

未完,待續…

一直都在努力,希望您也是!

微信搜索公眾號:就用python

作者:梁莉莉|編輯排版:李 鋒 

 


免責聲明!

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



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