Python爬蟲練習(一) 爬取筆趣閣小說(搜索+爬取)


 爬取筆趣閣小說(搜索+爬取)

首先看看最終效果(gif):

實現步驟:1.探查網站“http://www.xbiquge.la/”,看看網站的實現原理。

     2.編寫搜索功能(獲取每本書目錄的URL)。

     3.編寫寫入功能(按章節寫入文件)。

     4.完善代碼(修修bug,建了文件夾)。

ps:所需模塊 

1 import requests     
2 import bs4          # 爬網站必備兩個模塊不解釋
3 import os           # 用來創建文件夾的
4 import sys          # 沒啥用單純為了好看
5 import time         
6 import random       # 使用隨機數設置延時

 

 

一、網站搜索原理,並用Python實現。

我本以為這個網站和一般網站一樣,通過修改URL來進行搜索,結果並不然。

 可以看出這個網站不會因搜索內容改變而改變URL。

 那還有一種可能:通過POST請求,來更新頁面。讓我們打開Network驗證一下。

 

我的猜想是對的。接下來開始模擬。

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36",
    "Cookie": "_abcde_qweasd=0; Hm_lvt_169609146ffe5972484b0957bd1b46d6=1583122664; bdshare_firstime=1583122664212; Hm_lpvt_169609146ffe5972484b0957bd1b46d6=1583145548",
    "Host": "www.xbiquge.la"}      # 設置頭盡量多一點 以防萬一
x = str(input("輸入書名或作者名:"))   # 通過變量來控制我們要搜索的內容
data = {'searchkey': x}
url = 'http://www.xbiquge.la/modules/article/waps.php'
r = requests.post(url, data=data, headers=headers)
soup = bs4.BeautifulSoup(r.text.encode('utf-8'), "html.parser") # 用BeautifulSoup方法方便我們提取網頁內容網頁

可是如果現在我printf(soup)后發現里面的中文全為亂碼!

 這不難看出是編碼格式不對,但我們可以用encoding方法來獲取編碼方式。

 改完編碼后就可以正常提取了,並且和瀏覽器顯示的一致,都是我們搜索的內容。

 

 

 

二、接下來我們就來在這一堆代碼里找到我們想要的內容了(書名,作者,目錄URL)

通過元素審查我們很容易就可以定位到它們所在位置。

鏈接和書名在"td class even"<a>標簽里,作者在"td class=even"里。

什么!標簽重名了!怎么辦!管他三七二十一!先把"td class=even"全打印出來看看。

1 book_author = soup.find_all("td", class_="even")
2 for each in book_author:
3     print(each)

 可以發現每個each分為兩層。

那我們可以奇偶循環來分別處理這兩層。(因為如果不分層處理的話第一層要用的方法(each.a.get("href")在第二層會報錯,好像try也可以處理這個錯,沒試) 

並且用創建兩個三個列表來儲存三個值。

 1 books = []          #  書名
 2 authors = []        #  作者名
 3 directory = []      #  目錄鏈接
 4 tem = 1
 5 for each in book_author:
 6     if tem == 1:
 7         books.append(each.text)
 8         tem -= 1
 9         directory.append(each.a.get("href"))
10     else:
11         authors.append(each.text)
12         tem += 1

 

 成功!三個列表全部一樣對應!

那么要如何實現選擇一個序號,來讓Python獲得一個目錄鏈接呢?

我們可以這樣:

1 print('搜索結果:')
2 for num,book, author in zip(range(1, len(books)+1),books, authors):
3     print((str(num)+": ").ljust(4)+(book+"\t").ljust(25) + ("\t作者:" + author).ljust(20))
4 search = dict(zip(books, directory))

這樣打印出來的效果就是這樣了:

 是不是很神奇!“search”是我們用書名和目錄URL組成的字典,我們只要

return search[books[i-1]]

就可以讓下一個函數得到這本書的目錄URL了。

三、獲取章節URL,獲取文本內容,寫入文件。
  我們得到目錄的URL后就可以用相同的方法獲取每一章節的URL了(不贅述了)。
 1 def get_text_url(titel_url):
 2     url = titel_url
 3     global headers
 4     r = requests.get(url, headers=headers)
 5     soup = bs4.BeautifulSoup(r.text.encode('ISO-8859-1'), "html.parser")
 6     titles = soup.find_all("dd")
 7     texts = []
 8     names = []
 9     texts_names = []
10     for each in titles:
11         texts.append("http://www.xbiquge.la"+each.a["href"])
12         names.append(each.a.text)
13     texts_names.append(texts)
14     texts_names.append(names)
15     return texts_names          #  注意這里的返回值是一個包含兩個列表的列表!!
注意這里的返回值是一個包含兩個列表的列表!!
texts_names[0]就是每一章節的URL,
texts_names[0]是章節名
為下一個寫內容的函數方便調用。
接下來接是寫文件了!
 1 search = dict(zip(books, directory))
 2 url = texts_url[0][n]
 3 name = texts_url[1][n]      
 4 req = requests.get(url=url, headers=headers)
 5 time.sleep(random.uniform(0, 0.5))  # 即使設置了延遲,他還有會可能503(沒辦法小網站)
 6 req.encoding = 'UTF-8'  # 這里的編碼是UTF-8,跟目錄不一樣,要注意!
 7 html = req.text
 8 soup = bs4.BeautifulSoup(html, features="html.parser")
 9 texts = soup.find_all("div", id="content")
10 while (len(texts) == 0):  # 他如果503的話,讀取內容就什么都木有,那直接讓他再讀一次,直到讀出來為止。
11     req = requests.get(url=url, headers=headers)
12     time.sleep(random.uniform(0, 0.5))
13     req.encoding = 'UTF-8'
14     html = req.text
15     soup = bs4.BeautifulSoup(html, features="html.parser")
16     texts = soup.find_all("div", id="content")
17 else:
18     content = texts[0].text.replace('\xa0' * 8, '\n\n')
19     content = content.replace(
20         "親,點擊進去,給個好評唄,分數越高更新越快,據說給新筆趣閣打滿分的最后都找到了漂亮的老婆哦!手機站全新改版升級地址:http://m.xbiquge.la,數據和書簽與電腦站同步,無廣告清新閱讀!", "\n")
21     # 使用text屬性,提取文本內容,濾除br標簽,隨后使用replace方法,去掉八個空格符號,並用回車代替 再去除每一頁都有得結尾
22 with open(name + '.txt', "w", encoding='utf-8')as f:
23     f.write(content)
24     sys.stdout.write("\r已下載{}章,還剩下{}章".format(count, max - count))  # sys模塊就在這用了一次,為了不讓他換行。。。
25     count += 1
n就是章節的序列,直接for循環就可以把所有章節寫成文件了
這里處理503的方法雖然很暴力,可是是最有用的!


四、整理代碼,修修bug。

把上面的思路寫成三道四個函數打包一下。
然后測試一下,看看有什么bug,能修就修復,修復不了就直接try掉。(哈哈哈)
想要文件的可以研究研究os模塊,很簡單,這里不贅述了。
最后附上完整代碼!
  1 import requests
  2 import bs4          # 爬網站必備兩個模塊不解釋
  3 import os           # 用來創建文件夾的
  4 import sys          # 沒啥用單純為了好看
  5 import time
  6 import random       # 使用隨機數設置延時
  7 headers = {
  8     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36",
  9     "Cookie": "_abcde_qweasd=0; Hm_lvt_169609146ffe5972484b0957bd1b46d6=1583122664; bdshare_firstime=1583122664212; Hm_lpvt_169609146ffe5972484b0957bd1b46d6=1583145548",
 10     "Host": "www.xbiquge.la"}      # 設置頭盡量多一點 以防萬一
 11 b_n = ""
 12 def get_title_url():
 13     x = str(input("輸入書名或作者名:"))
 14     data = {'searchkey': x}
 15     url = 'http://www.xbiquge.la/modules/article/waps.php'
 16     global headers, b_n
 17     r = requests.post(url, data=data, headers=headers)
 18     soup = bs4.BeautifulSoup(r.text.encode('ISO-8859-1'), "html.parser")
 19     book_author = soup.find_all("td", class_="even")
 20     books = []          #  書名
 21     authors = []        #  作者名
 22     directory = []      #  目錄鏈接
 23     tem = 1
 24     for each in book_author:
 25         if tem == 1:
 26             books.append(each.text)
 27             tem -= 1
 28             directory.append(each.a.get("href"))
 29         else:
 30             authors.append(each.text)
 31             tem += 1
 32     print('搜索結果:')
 33     for num,book, author in zip(range(1, len(books)+1),books, authors):
 34         print((str(num)+": ").ljust(4)+(book+"\t").ljust(25) + ("\t作者:" + author).ljust(20))
 35     search = dict(zip(books, directory))
 36     if books == []:
 37         print("沒有找到任何一本書,請重新輸入!")
 38         get_title_url()
 39     try:
 40         i = int(input("輸入需要下載的序列號(重新搜索輸入'0')"))
 41     except:
 42         print("輸入錯誤重新輸入:")
 43         i = int(input("輸入需要下載的序列號(重新搜索輸入'0')"))
 44     if i == 0:
 45         books = []
 46         authors = []
 47         directory = []
 48         get_title_url()
 49     if i>len(books) or i<0:
 50         print("輸入錯誤重新輸入:")
 51         i = int(input("輸入需要下載的序列號(重新搜索輸入'0')"))
 52     b_n=books[i-1]
 53     try:
 54         os.mkdir(books[i-1])
 55         os.chdir(b_n)
 56     except:
 57         os.chdir(b_n)
 58         b_n = books[i - 1]
 59     return search[books[i-1]]
 60 
 61 def get_text_url(titel_url):
 62     url = titel_url
 63     global headers
 64     r = requests.get(url, headers=headers)
 65     soup = bs4.BeautifulSoup(r.text.encode('ISO-8859-1'), "html.parser")
 66     titles = soup.find_all("dd")
 67     texts = []
 68     names = []
 69     texts_names = []
 70     for each in titles:
 71         texts.append("http://www.xbiquge.la"+each.a["href"])
 72         names.append(each.a.text)
 73     texts_names.append(texts)
 74     texts_names.append(names)
 75     return texts_names          #  注意這里的返回值是一個包含兩個列表的列表!!
 76 
 77 
 78 def readnovel(texts_url):
 79     global headers,b_n
 80     count=1
 81     max=len(texts_url[1])
 82     print("預計耗時{}分鍾".format((max // 60)+1))
 83     tishi = input(str(b_n)+"一共{}章,確認下載輸入'y',輸入其他鍵取消".format(max))
 84     if tishi == "y"or tishi =="Y":
 85         for n in range(max):
 86             url = texts_url[0][n]
 87             name = texts_url[1][n]
 88             req = requests.get(url=url,headers=headers)
 89             time.sleep(random.uniform(0, 0.5))          # 即使設置了延遲,他還有會可能503(沒辦法小網站)
 90             req.encoding = 'UTF-8'                      # 這里的編碼是UTF-8,跟目錄不一樣,要注意!
 91             html = req.text
 92             soup = bs4.BeautifulSoup(html, features="html.parser")
 93             texts = soup.find_all("div", id="content")
 94             while (len(texts) == 0):                    #   他如果503的話,讀取內容就什么都木有,那直接讓他再讀一次,直到讀出來為止。
 95                 req = requests.get(url=url, headers=headers)
 96                 time.sleep(random.uniform(0,0.5))
 97                 req.encoding = 'UTF-8'
 98                 html = req.text
 99                 soup = bs4.BeautifulSoup(html, features="html.parser")
100                 texts = soup.find_all("div", id="content")
101             else:
102                 content = texts[0].text.replace('\xa0' * 8, '\n\n')
103                 content=content.replace("親,點擊進去,給個好評唄,分數越高更新越快,據說給新筆趣閣打滿分的最后都找到了漂亮的老婆哦!手機站全新改版升級地址:http://m.xbiquge.la,數據和書簽與電腦站同步,無廣告清新閱讀!","\n")
104                 # 使用text屬性,提取文本內容,濾除br標簽,隨后使用replace方法,去掉八個空格符號,並用回車代替 再去除每一頁都有得結尾
105             with open(name+'.txt',"w",encoding='utf-8')as f:
106                 f.write(content)
107                 sys.stdout.write("\r已下載{}章,還剩下{}章".format(count,max-count))     # sys模塊就在這用了一次,為了不讓他換行。。。
108                 count += 1
109         print("\n全部下載完畢")
110     else:
111         print("已取消!")
112         os.chdir('..')
113         os.rmdir(b_n)
114         main()
115 
116 def main():
117     titel_url = get_title_url()
118     texts_url = get_text_url(titel_url)
119     readnovel(texts_url)
120     input("輸入任意鍵退出")
121 
122 
123 if __name__ == '__main__':
124     print("小說資源全部來自於'新筆趣閣'---》http://www.xbiquge.la\n所以搜不到我也沒辦法..........@曉軒\n為了確保下載完整,每章設置了0.5秒到1秒延時!")
125     main()

 

 
       


免責聲明!

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



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