python书籍信息爬虫实例


Posted in Python onMarch 19, 2018

python书籍信息爬虫示例,供大家参考,具体内容如下

背景说明

需要收集一些书籍信息,以豆瓣书籍条目作为源,得到一些有效书籍信息,并保存到本地数据库。

获取书籍分类标签

具体可参考这个链接:
https://book.douban.com/tag/?view=type

然后将这些分类标签链接存到本地某个文件,存储内容如下

https://book.douban.com/tag/小说
https://book.douban.com/tag/外国文学
https://book.douban.com/tag/文学
https://book.douban.com/tag/随笔
https://book.douban.com/tag/中国文学
https://book.douban.com/tag/经典
https://book.douban.com/tag/日本文学
https://book.douban.com/tag/散文
https://book.douban.com/tag/村上春树
https://book.douban.com/tag/诗歌
https://book.douban.com/tag/童话
......

获取书籍信息,并保存本地数据库

假设已经建好mysql表,如下:

CREATE TABLE `book_info` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `bookid` varchar(64) NOT NULL COMMENT 'book ID',
 `tag` varchar(32) DEFAULT '' COMMENT '分类目录',
 `bookname` varchar(256) NOT NULL COMMENT '书名',
 `subname` varchar(256) NOT NULL COMMENT '二级书名',
 `author` varchar(256) DEFAULT '' COMMENT '作者',
 `translator` varchar(256) DEFAULT '' COMMENT '译者',
 `press` varchar(128) DEFAULT '' COMMENT '出版社',
 `publishAt` date DEFAULT '0000-00-00' COMMENT '出版日期',
 `stars` float DEFAULT '0' COMMENT '评分',
 `price_str` varchar(32) DEFAULT '' COMMENT '价格string',
 `hotcnt` int(11) DEFAULT '0' COMMENT '评论人数',
 `bookdesc` varchar(8192) DEFAULT NULL COMMENT '简介',
 `updateAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改日期',
 PRIMARY KEY (`id`),
 UNIQUE KEY `idx_bookid` (`bookid`),
 KEY `idx_bookname` (`bookname`),
 KEY `hotcnt` (`hotcnt`),
 KEY `stars` (`stars`),
 KEY `idx_tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='书籍信息';

并已实现相关爬虫逻辑,主要用到了BeautifulSoup包,如下:

#!/usr/bin/python
# coding: utf-8

import re
import logging
import requests
import pymysql
import random
import time
import datetime
from hashlib import md5
from bs4 import BeautifulSoup

logging.basicConfig(level=logging.INFO,
     format='[%(levelname)s][%(name)s][%(asctime)s]%(message)s',
     datefmt='%Y-%m-%d %H:%M:%S')

class DestDB:
 Host = "192.168.1.10"
 DB = "spider"
 Table = "book_info"
 User = "test"
 Pwd = "123456"

def connect_db(host, db, user, pwd):
 conn = pymysql.connect(
  host=host,
  user=user,
  passwd=pwd,
  db=db,
  charset='utf8',
  connect_timeout=3600) #,
#  cursorclass=pymysql.cursors.DictCursor)
 conn.autocommit(True)
 return conn

def disconnect_db(conn, cursor):
 cursor.close()
 conn.close()

#提取评价人数,如果评价人数少于10人,按10人处理
def hotratings(person):
 try:
  ptext = person.get_text().split()[0]
  pc = int(ptext[1:len(ptext)-4])
 except ValueError:
  pc = int(10)
 return pc

# 持久化到数据库
def save_to_db(tag, book_reslist):
 dest_conn = connect_db(DestDB.Host, DestDB.DB, DestDB.User, DestDB.Pwd)
 dest_cursor = dest_conn.cursor()

 isql = "insert ignore into book_info "
 isql += "(`bookid`,`tag`,`author`,`translator`,`bookname`,`subname`,`press`,"
 isql += "`publishAt`,`price_str`,`stars`,`hotcnt`,`bookdesc`) values "
 isql += ",".join(["(%s)" % ",".join(['%s']*12)]*len(book_reslist))

 values = []
 for row in book_reslist:
  # 暂时将md5(bookname+author)作为bookid唯一指
  bookid = md5(("%s_%s"%(row[0],row[2])).encode('utf-8')).hexdigest()
  values.extend([bookid, tag]+row[:10])

 dest_cursor.execute(isql, tuple(values))
 disconnect_db(dest_conn, dest_cursor)

# 处理每一次访问的页面
def do_parse(tag, url):
 page_data = requests.get(url)
 soup = BeautifulSoup(page_data.text.encode("utf-8"), "lxml")
 # 提取标签信息
 tag = url.split("?")[0].split("/")[-1]
 # 抓取作者,出版社信息
 details = soup.select("#subject_list > ul > li > div.info > div.pub")
 # 抓取评分
 scores = soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.rating_nums")
 # 抓取评价人数
 persons = soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.pl")
 # 抓取书名
 booknames = soup.select("#subject_list > ul > li > div.info > h2 > a")
 # 抓取简介 
 descs = soup.select("#subject_list > ul > li > div.info > p")
 # 从标签信息中分离内容
 book_reslist = []
 for detail, score, personCnt, bookname, desc in zip(details, scores, persons, booknames, descs):
  try:
   subtitle = ""
   title_strs = [s.replace('\n', '').strip() for s in bookname.strings]
   title_strs = [s for s in title_strs if s]
   # 部分书籍有二级书名
   if not title_strs:
    continue
   elif len(title_strs) >= 2:
    bookname, subtitle = title_strs[:2]
   else:
    bookname = title_strs[0]

   # 评分人数
   hotcnt = hotratings(personCnt)
   desc = desc.get_text()
   stars = float('%.1f' % float(score.get_text() if score.get_text() else "-1"))

   author, translator, press, publishAt, price = [""]*5
   detail_texts = detail.get_text().replace('\n', '').split("/")
   detail_texts = [s.strip() for s in detail_texts]

   # 部分书籍无译者信息
   if len(detail_texts) == 4:
    author, press, publishAt, price = detail_texts[:4]
   elif len(detail_texts) >= 5:
    author, translator, press, publishAt, price = detail_texts[:5]
   else:
    continue

   # 转换出版日期为date类型
   if re.match('^[\d]{4}-[\d]{1,2}', publishAt):
    dts = publishAt.split('-')
    publishAt = datetime.date(int(dts[0]), int(dts[1]), 1)
   else:
    publishAt = datetime.date(1000, 1, 1)

   book_reslist.append([author, translator, bookname, subtitle, press, 
         publishAt, price, stars, hotcnt, desc])
  except Exception as e:
   logging.error(e)

 logging.info("insert count: %d" % len(book_reslist))
 if len(book_reslist) > 0:
  save_to_db(tag, book_reslist)
  book_reslist = []
 return len(details)

def main():
 with open("book_tags.txt") as fd:
  tags = fd.readlines()
  for tag in tags:
   tag = tag.strip()
   logging.info("current tag url: %s" % tag)
   for idx in range(0, 1000000, 20):
    try:
     url = "%s?start=%d&type=T" % (tag.strip(), idx)
     cnt = do_parse(tag.split('/')[-1], url)
     if cnt < 10:
      break
     # 睡眠若干秒,降低访问频率
     time.sleep(random.randint(10, 15))
    except Exception as e:
     logging.warn("outer_err: %s" % e)
   time.sleep(300)

if __name__ == "__main__":
 main()

小结

以上代码基于python3环境来运行;
需要首先安装BeautifulSoup: pip install bs4
爬取过程中需要控制好访问频率;
需要对一些信息进行异常处理,比如译者信息、评论人数等。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python正则表达式匹配中文用法示例
Jan 17 Python
Python 编码Basic Auth使用方法简单实例
May 25 Python
Python使用微信SDK实现的微信支付功能示例
Jun 30 Python
Python编程实现使用线性回归预测数据
Dec 07 Python
python实现一个简单的并查集的示例代码
Mar 19 Python
python递归函数绘制分形树的方法
Jun 22 Python
django最快程序开发流程详解
Jul 19 Python
Python学习笔记之文件的读写操作实例分析
Aug 07 Python
Django错误:TypeError at / 'bool' object is not callable解决
Aug 16 Python
6行Python代码实现进度条效果(Progress、tqdm、alive-progress​​​​​​​和PySimpleGUI库)
Jan 06 Python
Python导入数值型Excel数据并生成矩阵操作
Jun 09 Python
解决Keras 自定义层时遇到版本的问题
Jun 16 Python
python中字符串比较使用is、==和cmp()总结
Mar 18 #Python
Python使用zip合并相邻列表项的方法示例
Mar 17 #Python
Python zip()函数用法实例分析
Mar 17 #Python
Python iter()函数用法实例分析
Mar 17 #Python
Python callable()函数用法实例分析
Mar 17 #Python
Python matplotlib绘图可视化知识点整理(小结)
Mar 16 #Python
python中matplotlib的颜色及线条控制的示例
Mar 16 #Python
You might like
dedecms采集中可以过滤多行代码的正则表达式
2007/03/17 PHP
Apache2中实现多网站域名绑定的实现方法
2011/06/01 PHP
PHP实现自动登入google play下载app report的方法
2014/09/23 PHP
PHP合并静态文件详解
2014/11/14 PHP
php利用cookies实现购物车的方法
2014/12/10 PHP
PHP异常处理浅析
2015/05/12 PHP
Ecshop 后台添加新功能栏目及管理权限设置教程
2017/11/21 PHP
PHP日期和时间函数的使用示例详解
2020/08/06 PHP
返回对象在当前级别中是第几个元素的实现代码
2011/01/20 Javascript
javascript使用isNaN()函数判断变量是否为数字
2013/09/21 Javascript
jquery 删除cookie失效的解决方法
2013/11/12 Javascript
jQuery实现的多级下拉菜单效果代码
2015/08/24 Javascript
Bootstrap 源代码分析(未完待续)
2016/08/17 Javascript
jQuery checkbox选中问题之prop与attr注意点分析
2016/11/15 Javascript
详解JavaScript的闭包、IIFE、apply、函数与对象
2016/12/21 Javascript
浅析vue中常见循环遍历指令的使用 v-for
2018/04/18 Javascript
使用vue-cli(vue脚手架)快速搭建项目的方法
2018/05/21 Javascript
python3生成随机数实例
2014/10/20 Python
python实现一次创建多级目录的方法
2015/05/15 Python
使用Python导出Excel图表以及导出为图片的方法
2015/11/07 Python
Python 实现淘宝秒杀的示例代码
2018/01/02 Python
django使用haystack调用Elasticsearch实现索引搜索
2019/07/24 Python
python numpy 反转 reverse示例
2019/12/04 Python
解决Python3.8用pip安装turtle-0.0.2出现错误问题
2020/02/11 Python
css3中新增的样式使用示例附效果图
2014/08/19 HTML / CSS
售后主管岗位职责
2013/12/08 职场文书
车贷收入证明范本
2014/09/14 职场文书
2014年最新领导班子整改方案
2014/09/27 职场文书
自愿离婚协议书范本
2015/01/26 职场文书
教师节老师寄语
2015/05/28 职场文书
太空授课观后感
2015/06/17 职场文书
七年级数学教学反思
2016/02/17 职场文书
高一数学教学反思
2016/02/18 职场文书
centos8安装MongoDB的详细过程
2021/10/24 MongoDB
Go语言基础函数基本用法及示例详解
2021/11/17 Golang
VS2019连接MySQL数据库的过程及常见问题总结
2021/11/27 MySQL