簡介
上一章節小編用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點感覺比較難處理:
- 小說名稱與URL的存入和取出,建議打印出來后對照着來調試取值會快很多。
- input的使用位置存放的不好,后來經過和小伙伴的談論后進行了重新修改,代碼整體舒服多了。
以上總結或許能幫助到你,或許幫助不到你,但還是希望能幫助到你,如有疑問、歧義,直接私信留言會及時修正發布;非常期待你的點贊和分享喲,謝謝!
未完,待續…
一直都在努力,希望您也是!
微信搜索公眾號:就用python
作者:梁莉莉|編輯排版:李 鋒