python爬蟲之抓取小說(逆天邪神)


2022-03-06 23:05:11

申明:自我娛樂,對自我學習過程的總結。

正文:

環境:

  1. 系統:win10,

  2. python版本:python3.10.2,

  3. 工具:pycharm。

項目目標:

  1. 實現對單本小說的更新判斷,省去人工登錄瀏覽器看小說的繁瑣操作。

  2. 如果小說內容更新了,那么自動下載你沒看過的小說內容到本地,並保存為txt格式。

  3. 對項目代碼封裝成可單獨運行在win10上的exe文件。

最終效果:都已實現。可以判斷小說更新了沒;更新了就下載下來;通過調整小說的已看章節數(就是你上次瀏覽小說章節位置記錄)可以達到直接保存整本小說。

項目實現流程:

1. 主程序

我這里只寫了一個main.py,就一個主函數解決了。

# 這個是一個爬取小說的工具
# 內容針對逆天邪神
# 功能1:是判斷小說是否更新,如果更新就下載下來
# 功能2:下載整本小說(單線程),一般都是自動下載最新更新的幾章,單線程足夠。——懶


import requests
import re
from bs4 import BeautifulSoup
import os

if __name__ == '__main__':
   novel_url = "https://www.bige3.com/book/1030/"  # 逆天邪神
   return_value = is_update(novel_url)  # 更新章節數
   if return_value == 0:
       print("小說尚未更新!")
   else:
       print("小說已更新" + str(return_value) +"章!")
       print("正在下載已更新的小說......")
       download_novel(return_value)
   # os.system("pause")   # 調試時注釋掉,封裝時打開,用於觀察結果

2. 功能函數

2.1 功能函數is_update()

def is_update(url):
   heards = {
       "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
  }
   try:
       resp = requests.get(url, headers=heards)
       resp.raise_for_status()  # 檢查Response狀態碼,若不是200則產生HttpError異常
       resp.encoding = 'utf-8'
   except:
       print("爬取失敗")

   resp = re.findall(r'<a href =.*?>(.*?)</a>', resp.text)
   # print("請求返回的列表中的最后一章是:" + resp[-1])
   with open("小說更新記錄.txt", "r", encoding='utf-8') as f:  # 打開文件
       data = f.read()  # 讀取文件
       # print("source_novel_data is:" + str(data))
   if data == str(resp[-1]):
       # print("===章節一致,小說尚未更新!")
       return 0
   else:
       # print("!==小說更新啦,並將更新值加入到小說更新記錄.txt")
       data_num = re.findall(r'\d+', data)  # list
       data_num = ''.join(data_num)  # str
       resp_num = re.findall(r'\d+', resp[-1])
       resp_num = ''.join(resp_num)
       gap_num = int(resp_num)-int(data_num)  # 更新章節數
       with open("小說更新記錄.txt", "w", encoding='utf-8') as f:  # 打開文件
           f.write(str(resp[-1]))  # 讀取文件
           print("writing is ok!")
       return gap_num
   

2.2 功能函數download_novel(return_value)

# 單線程方式
def download_novel(return_value):
   if return_value >= 1:
       for i in range(1, return_value+1, 1):
           print(i)
           with open("小說更新記錄.txt", "r", encoding='utf-8') as f:  # 打開文件
               data = f.read()  # 讀取文件 str
               data_num = re.findall(r'\d+', data)  # list
               data_num = ''.join(data_num)  # str
               download_num = int(data_num)+1-(i-1)
               # print(download_num)
               print(novel_url+str(download_num)+'.html')
           resp = requests.get(novel_url+str(download_num)+'.html')
           # print(resp.content)
           soup = BeautifulSoup(resp.text, 'lxml')
           soup.select('#chaptercontent')
           mytxt = soup.text[soup.text.find('下一章'):soup.text.rfind('『點此報錯')]
           mytxt = mytxt[3:]
           mytxt = mytxt.strip()
           mytxt = mytxt.replace('  ', '\n')
           novel_save_location = "./novel_downloads/逆天邪神第"+str(download_num-1)+"章.txt"
           with open(novel_save_location, "w", encoding='utf-8') as f:  # 打開文件
               f.write(mytxt)
           print("下載完畢!")
   else:
       print("invalid parameter!")

注意:

  1. 調試時要創建文件夾novel_downloads,並標注為Exclusion,防止pycharm自動創建索引,使電腦卡頓。

  2. 封裝后的main.exe要保證它所在的路徑下有兩個東西:文件夾novel_downloads和文件小說更新記錄.txt

  3. 初始階段保證文件小說更新記錄.txt里有個數字就行,隨便啥(1 or 1935等)

全部代碼:(直接能爬)

# 這個是一個爬取小說的工具
# 內容針對逆天邪神
# 功能1:是判斷小說是否更新,如果更新就下載下來
# 功能2:下載整本小說(單線程),一般都是自動下載最新更新的幾章,單線程足夠。——懶

import requests
from lxml import etree
import re
from bs4 import BeautifulSoup
import os

def is_update(url):
   heards = {
       "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
  }
   try:
       resp = requests.get(url, headers=heards)
       resp.raise_for_status()  # 檢查Response狀態碼,若不是200則產生HttpError異常
       resp.encoding = 'utf-8'
   except:
       print("爬取失敗")

   resp = re.findall(r'<a href =.*?>(.*?)</a>', resp.text)
   # print("請求返回的列表中的最后一章是:" + resp[-1])
   with open("小說更新記錄.txt", "r", encoding='utf-8') as f:  # 打開文件
       data = f.read()  # 讀取文件
       # print("source_novel_data is:" + str(data))
   if data == str(resp[-1]):
       # print("===章節一致,小說尚未更新!")
       return 0
   else:
       # print("!==小說更新啦,並將更新值加入到小說更新記錄.txt")
       data_num = re.findall(r'\d+', data)  # list
       data_num = ''.join(data_num)  # str
       resp_num = re.findall(r'\d+', resp[-1])
       resp_num = ''.join(resp_num)
       gap_num = int(resp_num)-int(data_num)  # 更新章節數
       with open("小說更新記錄.txt", "w", encoding='utf-8') as f:  # 打開文件
           f.write(str(resp[-1]))  # 讀取文件
           print("writing is ok!")
       return gap_num


# 單線程方式
def download_novel(return_value):
   if return_value >= 1:
       for i in range(1, return_value+1, 1):
           print(i)
           with open("小說更新記錄.txt", "r", encoding='utf-8') as f:  # 打開文件
               data = f.read()  # 讀取文件 str
               data_num = re.findall(r'\d+', data)  # list
               data_num = ''.join(data_num)  # str
               download_num = int(data_num)+1-(i-1)
               # print(download_num)
               print(novel_url+str(download_num)+'.html')
           resp = requests.get(novel_url+str(download_num)+'.html')
           # print(resp.content)
           soup = BeautifulSoup(resp.text, 'lxml')
           soup.select('#chaptercontent')
           mytxt = soup.text[soup.text.find('下一章'):soup.text.rfind('『點此報錯')]
           mytxt = mytxt[3:]
           mytxt = mytxt.strip()
           mytxt = mytxt.replace('  ', '\n')
           novel_save_location = "./novel_downloads/逆天邪神第"+str(download_num-1)+"章.txt"
           with open(novel_save_location, "w", encoding='utf-8') as f:  # 打開文件
               f.write(mytxt)
           print("下載完畢!")
   else:
       print("invalid parameter!")


if __name__ == '__main__':
   novel_url = "https://www.bige3.com/book/1030/"  # 逆天邪神
   return_value = is_update(novel_url)
   if return_value == 0:
       print("小說尚未更新!")
   else:
       print("小說已更新" + str(return_value) +"章!")
       print("正在下載已更新的小說......")
       download_novel(return_value)
   os.system("pause")

 

缺點:單線程,沒有用到異步協程,也沒有用線程池實現對小說下載章節數較多時的快速下載優勢。之后有空再優化代碼,並實現相應的功能。

實現效果:

例如章節是目前是

最新章節為:1936章 災厄奏鳴 ,我改個數字演示。

不改話,就沒有新章節更新:

改后跑起來,應該是

對應的文件夾里是:

 

打開后內容是:

 

Over!!!!!

封裝問題

步驟:

  1. 在pycharm項目路徑下打開終端輸入:pip install pyinstaller

  2. cd到項目的.py文件路徑下cd .\study_capture\novel_capture\

  3. 執行:pyinstaller -F .\main.py

結果是:

 

 

項目中用到的知識點:

這里面可以有些在優化程序時被我給去掉了,嘿嘿

請求網頁數據

resp = requests.get(url, headers=heards)

python中list與string的轉換

data_num = re.findall(r'\d+', data)  # 正則出來的是list 
data_num = ''.join(data_num)  # str

小說章節數的確認

resp = re.findall(r'<a href =.*?>(.*?)</a>', resp.text)

TXT文本的讀取

encoding='utf-8' 是有必要的,不然會報錯。

with open("小說更新記錄.txt", "r", encoding='utf-8') as f:  # 打開文件
   data = f.read()  # 讀取文件

TXT文本的回寫

with open("小說更新記錄.txt", "w", encoding='utf-8') as f:  # 打開文件
   f.write(str(resp[-1]))  # 讀取文件

BS4對HTML進行值的篩選

#表示識別標簽

soup = BeautifulSoup(resp.text, 'lxml')
soup.select('#chaptercontent')

取列表元素最后一個

resp[-1]

將列表中的章節數字拿出

data_num = re.findall(r'\d+', data)  # list

python特定位置的字符串截取

soup.text  str型
find('下一章') 左邊開始第一個索引
rfind('『點此報錯')   右邊開始第一個索引
mytxt = soup.text[soup.text.find('下一章'):soup.text.rfind('『點此報錯')]

字符串的拼接:

novel_save_location = "./novel_downloads/逆天邪神第"+str(download_num-1)+"章.txt"

小說保存時:

1.里面有空白,直接用

mytxt = mytxt.strip()

時沒有去掉,不知道啥原因。我記得聽網課說是:去掉空格,空白,換行符,其他好像都去了,最后還剩小說之間一些空白。

解決方式:因為沒有發現是啥符號(notepad++),於是之間將空白拿過來用(copy)。

mytxt=mytxt.replace('  ', '\n')
#目的是:在TXT文本中句子太長,於是我直接在每句話結束后換行。效果還行,與網站對比。

 

感謝觀看!!!第一次寫,好慢,好菜,回去寫作業去了。嗚嗚嗚

 


免責聲明!

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



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