環境:pycharm3.6 mysql django
爬蟲解析方式:bs4 +正則
爬取小說的網站: 筆下文學網 https://www.bxwxorg.com/
需求:擷取玄幻、武俠、都市、曆史 四類所有小說的資訊 ,包括6個字段(book_id,小說名,小說作者,小說簡介,小說最近更新時間,小說海報)
一、分析uirl:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL4VEVNlnVtJmdodEZ1I0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1gTO2ITM1ETMyETOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
點選進入玄幻類,發現共有50頁 ,每頁30本小說,點選第二頁 url發生變化:
通過頁數傳遞了參數 ,再來分析源代碼
然後再随便打開了一本小說 分析源代碼 :
發現是通過傳遞這本書的book_id 擷取這本書的具體資訊 ,于是要獲得4個類的所有小說的資訊,那麼前提是要獲得所有小說的book_id,再用book_id來逐個擷取需要字段的資訊。
二、爬蟲代碼實作
2.1 幾次探索發現 所有類(玄幻、武俠等)的小說的第一頁存儲小說的class id == 和後面的n頁是不相同的,這意味着第一頁和後面的response不能用一種方法來解析,是以我先處理了所有小說類的第一頁 ,然後在同時處理其他類的n頁。
spider代碼如下:
import requests
import re
import bs4
import time
import random
import pymysql
#列印報錯url日志
def log_error(url):
error_list=[]
error_list.append(url)
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134",
"Connection":"close"
}
#建立空清單存儲book_id
book_id_list=[]
#擷取各小說分類第一頁book_id
for i in ["xuanhuan","wuxia","dushi","lishi"]:
url="https://www.bxwxorg.com/"+i+"/1.html"
print(url)
response=requests.get(url=url,headers=headers)
bsoup = bs4.BeautifulSoup(response.text, "lxml")
bsoup1 = bsoup.find('div', class_='l')
# print(bsoup1)
li_list = bsoup1.find_all('li')
# print(li_list)
for book_info in li_list:
book = book_info.a.attrs['href']
# 正規表達式比對 提取book_id
book_id=re.findall("\d+", book)[0]
book_id_list.append(book_id)
#擷取其他頁的book_id
for m in ["xuanhuan", "wuxia", "dushi", "lishi"]:
for n in range(2,11):
try:
url = "https://www.bxwxorg.com/" + m + "/"+str(n)+".html"
print(url)
# 擷取每一頁小說的資訊
response =requests.get(url=url, headers=headers,timeout=1)
bsoup = bs4.BeautifulSoup(response.text, "lxml")
bsoup1 = bsoup.find('div', class_='novelslist2')
# print(bsoup1)
li_list = bsoup1.find_all('li')
li_list.pop(0)
for book_info in li_list:
book = book_info.a.attrs['href']
# 正規表達式比對 提取book_id
book_id = re.findall("\d+", book)[0]
book_id_list.append(book_id)
except requests.exceptions.RequestException:
url="https://www.bxwxorg.com/" + m + "/"+str(n)+".html"
log_error(url)
print(book_id_list)
for y in book_id_list:
try:
book_inf_url="https://www.bxwxorg.com/read/"+y+"/"
print(book_inf_url)
book_inf_response=requests.get(url=book_inf_url,headers=headers,timeout=(3,5))
#生成bs4對象
book_inf_bsoup=bs4.BeautifulSoup(book_inf_response.text,'lxml')
books_inf_bsoup1 = book_inf_bsoup.find('div', id='maininfo')
books_inf_img = book_inf_bsoup.find('img')
# 擷取圖檔位址
img_src = books_inf_img.attrs['src']
print(img_src)
# 擷取小說名
book_name = books_inf_bsoup1.h1.text
print(book_name)
# 擷取作者資訊
book_author = books_inf_bsoup1.find('p').text.split(":")[1]
print(book_author)
# 擷取最後更新時間
book_update_time = books_inf_bsoup1.find_all('p')[2].text.split(":")[1]
print(book_update_time)
# 擷取小說簡介
book_introduce = books_inf_bsoup1.find_all('p')[4].text
print(book_introduce)
#建立一個集合存每部小說的資訊
book_set={"book_id":y,"book_name":book_name,"book_author":book_author,
"book_introduce":book_introduce,"book_update_time":book_update_time,
"img_src":img_src}
second=random.randrange(2,3)
time.sleep(second)
因為比較簡單,是以就沒有做代碼優化,看起來比較臃腫,輕噴!
然後就是将爬到的資料存儲到mysql
代碼如下:
con = pymysql.connect(
host="localhost",
db="bxwx",
user="root",
port=3306,
passwd="123456",
charset="utf8",
use_unicode=True,
)
cur = con.cursor()
cur.execute('INSERT INTO bxwx_info(book_id,book_name,book_author,book_introduce,book_update_time,img_src) VALUES(%s,%s,%s,%s,%s,%s)',
(book_set['book_id'],book_set['book_name'],book_set['book_author'],book_set['book_introduce'],book_set['book_update_time'],book_set['img_src']))
con.commit()
# 關閉遊标和連接配接
cur.close()
con.close()
except requests.exceptions.RequestException:
book_inf_url = "https://www.bxwxorg.com/read/" + y + "/"
log_error(book_inf_url)
結果展示:
過程中遇到的問題:
1、HTTP連接配接錯誤:因為一開始我想把4個類所有的小說資料爬取下來 ,然後按照我這種方法,将會在較短時間内請求伺服器很多次,我算了下 4個類一共有 6000本小說,意味着爬蟲爬完需要連續請求6000次,不出意外,爬到一半報http連接配接錯誤。分析了原因是可能是因為網速或者網站伺服器的原因,請求有些小說的時候會出現 請求較長時間但是伺服器沒有response,于是我将代碼做了調整,在resquest函數的參數中加入了timeout= ** ,timeout包含了兩部分【請求時間+閱讀時間】 ,超過這個時間就會結束請求,并且報連接配接錯誤,我用try…except擷取了這個錯誤,并調用longin()函數,将報錯的url放進清單,後面可以統一處理 。 并且用了sleep,發現sleep的時間設定越長,爬蟲就越穩定,但效率就很低。
2、資料庫存儲報錯:資料存儲時,為了後面項目友善調用,将book_id設定為了主鍵,然而爬下來的資料有些book_id是重複的,以至于這些小說的資料未存儲成功,可解決方案【設計資料表時将小說名和book_id都設定為主鍵】
到這裡爬蟲+存儲到mysql就結束了,下面就是用django做搜尋界面展示了,詳情請檢視下一篇文章:pyhon爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【django搜尋呈現階段】