BeautifulSoup爬虫之保存到mysql数据库

爬取起点中文网 数据保存到mysql数据库

一.分析网页

目标网站:起点中文网

目标数据:类别(categoryName)小说书名(bookName) 小说链接(middleUrl)字数(wordsNums) 作者(updateTiems) 最新章节更新时间(authorName)

这里写图片描述

目标urls:”https://www.qidian.com/all?chanId=1&orderId=&style=2&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=1” 我们选取奇幻类的作测试 把page移动到最后方便后面的url拼接。

二.获取urls列表
1.取总页数
我们爬取多页的数据这时候就需要多个url了,根据上面的分析我们知道每一页page都不同所以我们只要改变url最后的”page=”就可以了 ,如果我们想获取这个系列所有的页数我们可以定位总页数。如图:

这里写图片描述
代码如下:

#总取页数
    def getPages(self,url):
        htmlContent = self.getResponseContent(url)
        soup = BeautifulSoup(htmlContent, 'lxml')
        tags=soup.find('ul',attrs={'class':'lbf-pagination-item-list'})
        #totalPages=tags.find_all('a')[-2].get('data-page') 取总页数
        totalPages=1  #测试用
        self.log.info(u'总页数为%s' %totalPages)
        return  totalPages

2.根据总页数拼接url

# 根据pageSum拼装要爬取的地址
    def getUrls(self,urlBase,pages):
        ulrs=[]
        ul=self.urlBase.split('=')
        for  i in range(int(pages)+1):
            ul[-1]=str(i)
            url='='.join(ul)
            ulrs.append(url)
            self.log.debug('----待爬取的地址有:' + url)
        return  ulrs

三.爬取目标数据
有了url我们就可以开始爬取我们想要的数据了!记得分析网页来进行元素定位。

#数据爬取 利用lxml解析
    def spider(self,urls):
        for ulr in urls:
            htmlContent = self.getResponseContent(url)
            soup = BeautifulSoup(htmlContent, 'lxml')
            tableTag=soup.find_all('table',attrs={'class':'rank-table-list all'})[0]
            trTags=tableTag.tbody.find_all('tr')
            for tag in trTags:
                item=BookItem()
                tags=tag.find_all('td')
                item.categoryName=tags[0].getText().strip()
                item.bookName=tags[1].getText().strip()
                item.middleUrl=tags[1].find('a').get('href').strip()
                item.wordsNums=tags[3].getText().strip()
                item.authorName=tags[4].getText().strip()
                item.updateTiems=tags[5].getText().strip()

                self.items.append(item)
                self.log.info(u'爬取%s 成功' %(item.categoryName))

四.保存数据到mysql
保存到text文本的方法这里就不再啰嗦。今天的重点是如何保存到mysql数据库。python提供了pymysql模块进行数据库相关操作
python 2—-> import MYSQLdb
python 3—-> import pymysql
没有安装记得安装pymysql
记得提前在数据库中建表!!!!!
建表:
这里写图片描述

代码如下:

#! -*- encoding:utf-8 -*-
"""
保存到mysql数据库

"""
import pymysql
pymysql.install_as_MySQLdb()

class SaveBooksDate(object):
    def __init__(self,items):
        self.host='localhost'
        self.port=3306
        self.user='root'
        self.password='a'
        self.db='test'
        self.run(items)

    def run(self,items):
        #创建连接
        conn=pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.password,db=self.db,charset='utf8')
        # 使用 cursor() 方法创建一个游标对象 cursor
        cur = conn.cursor()
        params=[]
        for item in items:
            params.append((item.categoryName, item.middleUrl, item.bookName, item.wordsNums, item.updateTiems,item.authorName))

        sql="insert into qidianbooks(categoryName,middleUrl,bookName,wordsNums,updateTiems,authorName) values(%s, %s, %s, %s, %s, %s )"
        try:
            # 执行SQL
            ret=cur.executemany(sql,params)
            conn.commit()   #提交
            print(u'添加成功,共添加%s 条数据' %str(ret))
        except  Exception as e:
            print(e)
            conn.rollback()
        cur.close() # 关闭游标
        conn.close()    # 关闭连接

这里是新建的文件 记得在爬虫文件引入函数以及调用SaveBooksDate()函数
引入:

from save2mysql import SaveBooksDate

调用:

    def __init__(self,url):
      self.urlBase=url
      self.log=MyLog()
      self.pages=self.getPages(self.urlBase)  #根据urlBase取页数
      self.items=[]
      self.urls=[]
      self.urls = self.getUrls(self.urlBase,self.pages)     #根据页数获取url
      # 开始爬取
      self.spider(self.urls)
      # 存
      #self.pipelines(self.items)
      #存入mysql
      SaveBooksDate(self.items)

连接数据库的时候出了个bug:
这里写图片描述
后来才发现太粗心了少了一个括号:
这里写图片描述

以后一定要细心细心再细心!

四.结果及源代码

结果:
这里写图片描述

注:直接在mysql中读取可能乱码 这里我用navicat查看!

1.日志类
代码:

#! -*- encoding:utf-8 -*-\

"""
乱码问题 解决方式一:#! -*- encoding:utf-8 -*-\
            方式二:u'哈哈哈'  字符串以unicode格式存储

"""
import logging
import getpass
import sys

class MyLog(object):
    #构造方法
    def __init__(self):
        self.user=getpass.getuser()
        self.logger=logging.getLogger(self.user)
        self.logger.setLevel(   logging.DEBUG )  #日志的级别    critical error warn info  debug

        #定义日志文件
        self.logFile=sys.argv[0][0:-3]+'.log'       # 从命令行参数中取出第一个参数,并取从0开始到   倒数第三个字符    拼接成文件名
        self.formatter=logging.Formatter('%(asctime) -12s %(levelname) -8s %(name) -10s %(message)-12s\r\n')  #日志输出的格式

        #日志输出到文件    logging有三个内置的Handler,
        self.logHand=logging.FileHandler(self.logFile, encoding='utf8')
        self.logHand.setFormatter(   self.formatter  )   #设置 格式
        self.logHand.setLevel(   logging.DEBUG )  #设置 级别

        #日志输出 到屏幕,这是标准输出流
        self.logHandSt=logging.StreamHandler()
        self.logHandSt.setFormatter(  self.formatter )
        self.logHand.setLevel(  logging.DEBUG )

        #将两个Handler加入到  logger中
        self.logger.addHandler(   self.logHand )
        self.logger.addHandler(    self.logHandSt )

    #重新定义logger中的日志输出的级别的方法
    def debug(self,msg):
        self.logger.debug(msg)

    def  info(self,msg):
        self.logger.info(msg)

    def warn(self,msg):
        self.logger.warn(msg)

    def error(self,msg):
        self.logger.error(msg)

    def critical(self,msg):
        self.logger.critical(msg)

if __name__=='__main__':
    mylog=MyLog()
    mylog.debug(u'debug测试')
    mylog.info(u'info测试')
    mylog.warn(u'warn测试')
    mylog.error(u'error测试')
    mylog.critical(u'critical测试')

2.爬虫类

代码:

#! -*- encoding:utf-8 -*-

#目标地址:https://www.qidian.com/all?chanId=1&orderId=&style=2&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=1
from MyLog import MyLog
import string
from urllib.parse import quote
from urllib import error
import urllib.request
from bs4 import BeautifulSoup
from save2mysql import SaveBooksDate
import  codecs
import time
import os

#pymysql
class BookItem(object):
    categoryName=None
    middleUrl=None
    bookName=None
    wordsNums= None
    updateTiems= None
    authorName= None


class GetBook(object):
    def __init__(self,url):
      self.urlBase=url
      self.log=MyLog()
      self.pages=self.getPages(self.urlBase)  #根据urlBase取页数
      self.items=[]
      self.urls=[]
      self.urls = self.getUrls(self.urlBase,self.pages)     #根据页数获取url
      # 开始爬取
      self.spider(self.urls)
      # 存
      #self.pipelines(self.items)
      SaveBooksDate(self.items)


    # 根据pageSum拼装要爬取的地址
    def getUrls(self,urlBase,pages):
        ulrs=[]
        ul=self.urlBase.split('=')
        for  i in range(int(pages)+1):
            ul[-1]=str(i)
            url='='.join(ul)
            ulrs.append(url)
            self.log.debug('----待爬取的地址有:' + url)
        return  ulrs
    #取页数
    def getPages(self,url):
        htmlContent = self.getResponseContent(url)
        soup = BeautifulSoup(htmlContent, 'lxml')
        tags=soup.find('ul',attrs={'class':'lbf-pagination-item-list'})
        #totalPages=tags.find_all('a')[-2].get('data-page')
        totalPages=1
        self.log.info(u'总页数为%s' %totalPages)
        return  totalPages

    #数据爬取 利用lxml解析
    def spider(self,urls):
        for ulr in urls:
            htmlContent = self.getResponseContent(url)
            soup = BeautifulSoup(htmlContent, 'lxml')
            tableTag=soup.find_all('table',attrs={'class':'rank-table-list all'})[0]
            trTags=tableTag.tbody.find_all('tr')
            for tag in trTags:
                item=BookItem()
                tags=tag.find_all('td')
                item.categoryName=tags[0].getText().strip()
                item.bookName=tags[1].getText().strip()
                item.middleUrl=tags[1].find('a').get('href').strip()
                item.wordsNums=tags[3].getText().strip()
                item.authorName=tags[4].getText().strip()
                item.updateTiems=tags[5].getText().strip()

                self.items.append(item)
                self.log.info(u'爬取%s 成功' %(item.categoryName))

    #读取URL指定的网页内容
    def getResponseContent(self,url):
        #对地址的中文进行编码
        try:
            url=quote(url,safe=string.printable)
            response=urllib.request.urlopen(url)
        except  error.URLError as e:
            self.log.error(u'python爬取%s 出错了' %url)
            print (e)
        else:
            self.log.info(u'python爬取%s 成功' %url)
            return response.read()

    #爬取的信息保存
    def pipelines(self, items):
        filePrefixName =time.strftime('%Y%m%H%M%s',time.localtime())
        fileName=os.path.expanduser("~")+os.path.sep+filePrefixName+u'.txt'
        with codecs.open(fileName, 'w', 'utf8') as fp:
            for item in items:
                fp.write('%s %s %s %s %s %s \n' % (item.categoryNam, item.bookName, item.middleUrl, item.wordsNums, item.authorName, item.updateTiems))
                self.log.info(u'标题为 %s 的小说信息保存成功' % (item.categoryNam))

if __name__=='__main__':
    url=u'https://www.qidian.com/all?chanId=1&orderId=&style=2&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=1'
    tb=GetBook(url)

"""
保存到mysql库
python 2    import MYSQLdb
python 3    import pymysql

"""

3.存数据库类

数据库代码如上—->四.保存数据到mysql
以后会写使用scrapy如何保存数据到mysql。大家也发现了仅仅一个分类就有几千页的数据使用爬虫爬取多页数据IP可能会被封掉以后我会结合实例演示如何反反爬虫。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值