前言 偶然一天把某項目文檔傳到手機上,用手機自帶的閱讀器方便隨時拿出來查閱。看著我那好久沒點開的閱讀器,再看著書架上擺著幾本不知道是多久之前導入的小說。 閉上眼,我仿佛看到那時候的自己。側躺著縮在被窩裡,亮度調到最低,看的津津有味。 睜開眼,一聲短嘆,心中五味雜陳,時間像箭一樣飛逝而去,過去靜止不動 ...
前言
偶然一天把某項目文檔傳到手機上,用手機自帶的閱讀器方便隨時拿出來查閱。看著我那好久沒點開的閱讀器,再看著書架上擺著幾本不知道是多久之前導入的小說。
閉上眼,我仿佛看到那時候的自己。側躺著縮在被窩裡,亮度調到最低,看的津津有味。
睜開眼,一聲短嘆,心中五味雜陳,時間像箭一樣飛逝而去,過去靜止不動,未來姍姍來遲。
正好最近又重溫了下python,準備做一個簡單的獲取小說txt文件的程式。
一、前期準備
1.安裝第三方庫
win + r 輸入cmd
命令行輸入
pip install requests
pip install pyquery
嫌麻煩pycharm直接搜索包安裝就行
2.感謝---支持
純屬愛好,僅供學習
二、主要步驟
1.請求網頁
老樣子,F12進控制台,輸入 document.chartset 查看網頁編碼
1 # 請求網頁 獲取網頁數據 2 def GetHTMLText(url: str) -> str: 3 res = requests.get(url=url, headers=GetHeader(), proxies=GetProxy()) 4 res.encoding = "GBK" 5 html: str = res.text 6 return html
2.獲取章節目錄
測試地址:---
Ctrl + Shift + C ,選擇章節目錄任意一章
可以發現章節目錄class="zjlist"下的<dd>標簽內含有每一章節的信息,該章節的url和章節名
代碼如下:
1 # 獲取章節目錄 2 def GetPageTree(doc: pQ) -> pQ: 3 pageTree: pQ = doc('.zjlist dd a') 4 return pageTree
3.輸入轉碼
GBK轉碼:
在搜索框內輸入名稱,searchkey=,後就是該名稱對應的GBK編碼
將鏈接後的編碼輸進進行解碼,得到你所輸入的文字內容
代碼如下:
1 # 輸入轉碼 獲取搜索到的書籍鏈接 2 def GetSearchUrl(Novel_Name: str) -> str: 3 StrToGbk: bytes = Novel_Name.encode("gbk") 4 GbkToStr: str = str(StrToGbk) 5 Url_input = GbkToStr[2:-1].replace("\\x", "%").upper() 6 Url = "---" + "searchtype=articlename&searchkey=" 7 return Url + Url_input
4.抓取模式
搜索到小說之後跳轉到搜索到的網頁,可能會出現兩種情況
一種是一次搜索到結果
還有一種是搜索到多種結果,需要對這個網頁再做一次解析篩選
判斷網頁容器的id="info",是否有這個節點
代碼如下:
1 # 抓取模式 2 def GetModel(doc: pQ) -> bool: 3 if doc('#info'): 4 return True # 一次搜索到,不需要篩選 5 else: 6 return False
三、代碼展示
1 import os 2 import requests 3 import time 4 import re 5 from random import choice 6 from pyquery import PyQuery as pQ 7 8 9 # 獲取請求頭 10 def GetHeader() -> dict: 11 header = [ # 請求頭 12 { 13 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36" 14 }, 15 { 16 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" 17 }, 18 { 19 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" 20 }, 21 { 22 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" 23 }, 24 { 25 "User-Agent": "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" 26 }, 27 { 28 "User-Agent": "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" 29 }, 30 { 31 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" 32 }, 33 { 34 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36" 35 }, 36 { 37 "User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)" 38 }, 39 { 40 "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50" 41 } 42 ] 43 return choice(header) 44 45 46 # 獲取代理 47 def GetProxy() -> dict: 48 proxies = [ # 代理 49 { 50 "Https": "60.170.204.30:8060" 51 }, 52 { 53 "Https": "103.37.141.69:80" 54 }, 55 { 56 "Https": "183.236.232.160:8080" 57 }, 58 { 59 "Https": "202.55.5.209:8090" 60 }, 61 { 62 "Https": "202.55.5.209:8090" 63 } 64 ] 65 return choice(proxies) 66 67 68 # 輸入轉碼 獲取搜索到的書籍鏈接 69 def GetSearchUrl(Novel_Name: str) -> str: 70 StrToGbk: bytes = Novel_Name.encode("gbk") 71 GbkToStr: str = str(StrToGbk) 72 Url_input = GbkToStr[2:-1].replace("\\x", "%").upper() 73 Url = "---" + "modules/article/search.php?searchtype=articlename&searchkey=" 74 return Url + Url_input 75 76 77 # 請求網頁 獲取網頁數據 78 def GetHTMLText(url: str) -> str: 79 res = requests.get(url=url, headers=GetHeader(), proxies=GetProxy()) 80 # Console --- document.charset ---'GBK' 81 res.encoding = "GBK" 82 html: str = res.text 83 return html 84 85 86 # 獲取網頁解析 87 def GetParse(url: str) -> pQ: 88 text = GetHTMLText(url) 89 doc: pQ = pQ(text) 90 return doc 91 92 93 # 獲取小說名 94 def GetNovelName(doc: pQ) -> str: 95 con = doc('#info') 96 novel_name: str = con('h1').text().split(' ')[0] 97 return novel_name 98 99 100 # 獲取章節目錄 101 def GetPageTree(doc: pQ) -> pQ: 102 pageTree: pQ = doc('.zjlist dd a') 103 return pageTree 104 105 106 # 提取章節鏈接跳轉後的頁面內容 id="content" 107 def GetNovel(url) -> str: 108 doc = GetParse(url) 109 con = doc('#content') 110 novel: str = con.text() 111 return novel 112 113 114 # 獲取總頁數 115 def GetPageNums(doc: pQ): 116 pageNums = doc('.form-control option') 117 return pageNums 118 119 120 # 獲取novel主頁鏈接 121 def GetHomeUrl(doc: pQ) -> str: 122 PageNums = GetPageNums(doc) 123 for page in PageNums.items(): 124 if page.text() == "第1頁": 125 return page.attr('value') 126 127 128 # 抓取模式 129 def GetModel(doc: pQ) -> bool: 130 if doc('#info'): 131 return True # 一次搜索到,不需要篩選 132 else: 133 return False 134 135 136 # 搜索到結果開始抓取 137 # Args_url---novel主頁鏈接 138 # ms---間隔時間,單位:ms 139 # url_ 主網站 140 def GetDate_1(Args_url: str, doc: pQ, ms: int, url_: str = "---") -> None: 141 NovelName = GetNovelName(doc) 142 PageNums = GetPageNums(doc) 143 file_path = os.getcwd() + "\\" + NovelName # 文件存儲路徑 144 setDir(file_path) # 判斷路徑是否存在,不存在創建,存在刪除 145 Seconds: float = ms / 1000.0 146 for page in PageNums.items(): 147 url = url_ + page.attr('value') # 每一頁的鏈接 148 currentPage = page.text() # 當前頁 149 doc: pQ = GetParse(url) 150 page_tree = GetPageTree(doc) 151 for page_Current in page_tree.items(): 152 page_name: str = page_Current.text() # 章節名 153 page_link = page_Current.attr('href') # 章節鏈接 154 novel = page_name + "\n\n" + GetNovel(Args_url + page_link) + "\n\n" # 文章內容 155 page_Name = clean_file_name(page_name) # 處理後的章節名 156 download_path = file_path + "\\" + NovelName + ".txt" # 文件下載路徑 157 with open(download_path, "a", encoding="utf-8") as f: 158 f.write(novel) 159 print("正在下載 {}...".format(page_Name)) 160 time.sleep(Seconds) 161 f.close() 162 print("{}下載成功\n".format(page_Name)) 163 print("{}下載完成\n".format(currentPage)) 164 print("{}下載完成!".format(NovelName)) 165 166 167 # 搜索到重覆結果,需要進行篩選.匹配成功返迴首頁的網址 168 def GetUrl_2(doc: pQ, SearchName: str) -> str: 169 con = doc('.odd a').items() 170 for Title in con: 171 if Title.text() == SearchName: 172 url: str = Title.attr('href') 173 return url 174 175 176 # 文件處理 177 def setDir(filepath): 178 if not os.path.exists(filepath): # 如果文件夾不存在就創建 179 os.mkdir(filepath) 180 else: 181 for i in os.listdir(filepath): # os.listdir(filepath)返回一個列表,裡面是當前目錄下麵的所有東西的相對路徑 182 file_data = filepath + "\\" + i # 當前文件夾下文件的絕對路徑 183 if os.path.isfile(file_data): 184 os.remove(file_data) # 文件存在-刪除 185 186 187 # 異常文件名處理 188 def clean_file_name(filename: str): 189 invalid_chars = '[\\\/:*??"<>|]' 190 replace_char = '-' 191 return re.sub(invalid_chars, replace_char, filename) 192 193 194 # 保存文件 195 def SaveFile(url: str, searchName: str): 196 doc = GetParse(url) 197 url_: str = "---" #懂得都懂 198 try: 199 if GetModel(doc): 200 url = url_ + GetHomeUrl(doc) 201 doc = doc 202 else: 203 url = GetUrl_2(doc, searchName) 204 doc = GetParse(url) 205 GetDate_1(Args_url=url, doc=doc, ms=100) 206 except Exception as result: 207 print("{}".format(result)) 208 finally: 209 print("請輸入有效書名") 210 211 212 # 輸入名字搜索 213 def main(): 214 SearchName = input("請輸入需要下載的書名:") 215 url = GetSearchUrl(SearchName) 216 SaveFile(url, SearchName) 217 218 219 if __name__ == "__main__": 220 main()View Code
四、運行效果
總結
按名稱搜索跟直接拿首頁鏈接原理差不多,只不過多了個篩選的操作
以上就是今天要分享的內容,時間原因還有很多可以優化的地方,後面有時間再改吧……
最後說說自己的一些想法,為什麼現在對小說沒什麼感覺了。
看小說除了讓我的鼻梁上戴著的東西越來越厚之外,還讓我的作息變得一團糟。我是個管不住自己的人,以前看小說最著迷的時候,除了吃飯睡覺,剩下時間全拿來看小說了。
當然,看小說也並不像我說的那樣百害無一利,但是要註意合理安排好自己的時間,勞逸結合。