天天看點

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

環境:pycharm3.6 mysql django

爬蟲解析方式:bs4 +正則

爬取小說的網站: 筆下文學網 https://www.bxwxorg.com/

需求:擷取玄幻、武俠、都市、曆史 四類所有小說的資訊 ,包括6個字段(book_id,小說名,小說作者,小說簡介,小說最近更新時間,小說海報)

一、分析uirl:

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

點選進入玄幻類,發現共有50頁 ,每頁30本小說,點選第二頁 url發生變化:

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

通過頁數傳遞了參數 ,再來分析源代碼

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

然後再随便打開了一本小說 分析源代碼 :

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

發現是通過傳遞這本書的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)
           

結果展示:

python爬取小說存儲至Mysql并用 django架構做了搜尋呈現界面【爬蟲-mysql階段】

過程中遇到的問題:

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搜尋呈現階段】