天天看点

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搜索呈现阶段】