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的id()函数解密过程
Dec 25 Python
python三元运算符实现方法
Dec 17 Python
Python字符串处理之count()方法的使用
May 18 Python
Python 多线程实例详解
Mar 25 Python
Python实现的概率分布运算操作示例
Aug 14 Python
基于pandas数据样本行列选取的方法
Apr 20 Python
Python解析、提取url关键字的实例详解
Dec 17 Python
Django 解决distinct无法去除重复数据的问题
May 20 Python
浅谈keras 模型用于预测时的注意事项
Jun 27 Python
基于python实现生成指定大小txt文档
Jul 20 Python
Python如何进行时间处理
Aug 06 Python
PyCharm+PyQt5+QtDesigner配置详解
Aug 12 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
利用PHP创建动态图像
2006/10/09 PHP
在Windows中安装Apache2和PHP4的权威指南
2006/10/09 PHP
PHP实现基于栈的后缀表达式求值功能
2017/11/10 PHP
基于laravel Request的所有方法详解
2019/09/29 PHP
php实现将数组或对象写入到文件的方法小结【三种方法】
2020/04/22 PHP
jquery 学习笔记一
2010/04/07 Javascript
Jquery调用webService远程访问出错的解决方法
2010/05/21 Javascript
jQuery判断元素是否是隐藏的代码
2011/04/24 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
JS 添加千分位与去掉千分位的示例
2013/07/11 Javascript
js操纵dom生成下拉列表框的方法
2014/02/24 Javascript
js判断上传文件类型判断FileUpload文件类型代码
2014/05/20 Javascript
总结JavaScript中布尔操作符||与&amp;&amp;的使用技巧
2015/11/17 Javascript
利用jQuery实现打字机字幕效果实例代码
2016/09/02 Javascript
JavaScript实现的搜索及高亮显示功能示例
2017/08/14 Javascript
vue-cli axios请求方式及跨域处理问题
2018/03/28 Javascript
Vue filter介绍及详细使用
2018/04/04 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
2019/07/10 jQuery
Python中的闭包总结
2014/09/18 Python
在pycharm中为项目导入anacodna环境的操作方法
2020/02/12 Python
PyQt5.6+pycharm配置以及pyinstaller生成exe(小白教程)
2020/06/02 Python
CSS3绘制超炫的上下起伏波动进度加载动画
2016/04/21 HTML / CSS
html5 canvas的绘制文本自动换行的示例代码
2018/09/17 HTML / CSS
荷兰家电购物网站:Expert.nl
2020/01/18 全球购物
速卖通欧盟:Aliexpress EU
2020/08/19 全球购物
Python中pass语句的作用是什么
2016/06/01 面试题
简历中个人求职的自我评价模板
2013/11/29 职场文书
自我评价正确写法范文
2013/12/10 职场文书
股票投资建议书
2014/05/19 职场文书
企业文化标语口号
2014/06/09 职场文书
高中学生会竞选演讲稿
2014/08/25 职场文书
敬老月活动总结
2014/08/28 职场文书
干部作风建设个人剖析材料
2014/10/11 职场文书
基层党员群众路线整改措施及努力方向
2014/10/28 职场文书
2014年控辍保学工作总结
2014/12/08 职场文书
阿里云ECS云服务器快照的概念以及如何使用
2022/04/21 Servers