Python多线程爬取豆瓣影评API接口


Posted in Python onOctober 22, 2019

爬虫库

使用简单的requests库,这是一个阻塞的库,速度比较慢。

解析使用XPATH表达式

总体采用类的形式

多线程

使用concurrent.future并发模块,建立线程池,把future对象扔进去执行即可实现并发爬取效果

数据存储

使用Python ORM sqlalchemy保存到数据库,也可以使用自带的csv模块存在CSV中。

API接口

因为API接口存在数据保护情况,一个电影的每一个分类只能抓取前25页,全部评论、好评、中评、差评所有分类能爬100页,每页有20个数据,即最多为两千条数据。

因为时效性原因,不保证代码能爬到数据,只是给大家一个参考思路,上代码:

from datetime import datetime
import random
import csv
from concurrent.futures import ThreadPoolExecutor, as_completed

from lxml import etree
import pymysql
import requests

from models import create_session, Comments

#随机UA
USERAGENT = [
  'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
  'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
  'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
  'Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50',
  'Mozilla/5.0 (Windows; U; Windows NT 6.1; ) AppleWebKit/534.12 (KHTML, like Gecko) Maxthon/3.0 Safari/534.12'
]


class CommentFetcher:
  headers = {'User-Agent': ''}
  cookie = ''
  cookies = {'cookie': cookie}
  # cookie为登录后的cookie,需要自行复制
  base_node = '//div[@class="comment-item"]'


  def __init__(self, movie_id, start, type=''):
    '''
    :type: 全部评论:'', 好评:h 中评:m 差评:l
    :movie_id: 影片的ID号
    :start: 开始的记录数,0-480
    '''
    self.movie_id = movie_id
    self.start = start
    self.type = type
    self.url = 'https://movie.douban.com/subject/{id}/comments?start={start}&limit=20&sort=new_score\&status=P&percent_type={type}&comments_only=1'.format(
      id=str(self.movie_id),
      start=str(self.start),
      type=self.type
    )
    #创建数据库连接
    self.session = create_session()

  #随机useragent
  def _random_UA(self):
    self.headers['User-Agent'] = random.choice(USERAGENT)


  #获取api接口,使用get方法,返回的数据为json数据,需要提取里面的HTML
  def _get(self):
    self._random_UA()
    res = ''
    try:
      res = requests.get(self.url, cookies=self.cookies, headers=self.headers)
      res = res.json()['html']
    except Exception as e:
      print('IP被封,请使用代理IP')
    print('正在获取{} 开始的记录'.format(self.start))
    return res

  def _parse(self):
    res = self._get()
    dom = etree.HTML(res)

    #id号
    self.id = dom.xpath(self.base_node + '/@data-cid')
    #用户名
    self.username = dom.xpath(self.base_node + '/div[@class="avatar"]/a/@title')
    #用户连接
    self.user_center = dom.xpath(self.base_node + '/div[@class="avatar"]/a/@href')
    #点赞数
    self.vote = dom.xpath(self.base_node + '//span[@class="votes"]/text()')
    #星级
    self.star = dom.xpath(self.base_node + '//span[contains(@class,"rating")]/@title')
    #发表时间
    self.time = dom.xpath(self.base_node + '//span[@class="comment-time "]/@title')
    #评论内容 所有span标签class名为short的节点文本
    self.content = dom.xpath(self.base_node + '//span[@class="short"]/text()')

  #保存到数据库
  def save_to_database(self):
    self._parse()
    for i in range(len(self.id)):
      try:
        comment = Comments(
          id=int(self.id[i]),
          username=self.username[i],
          user_center=self.user_center[i],
          vote=int(self.vote[i]),
          star=self.star[i],
          time=datetime.strptime(self.time[i], '%Y-%m-%d %H:%M:%S'),
          content=self.content[i]
        )

        self.session.add(comment)
        self.session.commit()
        return 'finish'


      except pymysql.err.IntegrityError as e:
        print('数据重复,不做任何处理')

      except Exception as e:
        #数据添加错误,回滚
        self.session.rollback()

      finally:
        #关闭数据库连接
        self.session.close()

  #保存到csv
  def save_to_csv(self):
    self._parse()
    f = open('comment.csv', 'w', encoding='utf-8')
    csv_in = csv.writer(f, dialect='excel')
    for i in range(len(self.id)):
      csv_in.writerow([
        int(self.id[i]),
        self.username[i],
        self.user_center[i],
        int(self.vote[i]),
        self.time[i],
        self.content[i]
      ])
    f.close()


if __name__ == '__main__':
  with ThreadPoolExecutor(max_workers=4) as executor:
    futures = []
    for i in ['', 'h', 'm', 'l']:
      for j in range(25):
        fetcher = CommentFetcher(movie_id=26266893, start=j * 20, type=i)
        futures.append(executor.submit(fetcher.save_to_csv))

    for f in as_completed(futures):
      try:
        res = f.done()
        if res:
          ret_data = f.result()
          if ret_data == 'finish':
            print('{} 成功保存数据'.format(str(f)))
      except Exception as e:
        f.cancel()

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

Python 相关文章推荐
Python 正则表达式操作指南
May 04 Python
Python模拟登录12306的方法
Dec 30 Python
python paramiko模块学习分享
Aug 23 Python
全面了解Nginx, WSGI, Flask之间的关系
Jan 09 Python
Python登录注册验证功能实现
Jun 18 Python
基于pandas将类别属性转化为数值属性的方法
Jul 25 Python
pandas重新生成索引的方法
Nov 06 Python
Python调用C语言程序方法解析
Jul 07 Python
Python是怎样处理json模块的
Jul 16 Python
如何查看python关键字
Jan 17 Python
教你使用Python pypinyin库实现汉字转拼音
May 27 Python
总结Python连接CS2000的详细步骤
Jun 23 Python
Python Process多进程实现过程
Oct 22 #Python
详解python中eval函数的作用
Oct 22 #Python
FFT快速傅里叶变换的python实现过程解析
Oct 21 #Python
python 采用paramiko 远程执行命令及报错解决
Oct 21 #Python
python文件读写代码实例
Oct 21 #Python
python 动态调用函数实例解析
Oct 21 #Python
python 两个数据库postgresql对比
Oct 21 #Python
You might like
利用PHP访问MySql数据库的逻辑操作以及增删改查的实例讲解
2017/08/30 PHP
PHP精确到毫秒秒杀倒计时实例详解
2019/03/14 PHP
php生成静态页面并实现预览功能
2019/06/27 PHP
JavaScript 判断判断某个对象是Object还是一个Array
2010/01/28 Javascript
一段实现页面上的图片延时加载的js代码
2010/02/11 Javascript
JavaScript实现同步于本地时间的动态时间显示方法
2015/02/02 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
kindeditor编辑器点中图片滚动条往上顶的bug
2015/07/05 Javascript
AngularJS  自定义指令详解及实例代码
2016/09/14 Javascript
JavaScript递归操作实例浅析
2016/10/31 Javascript
在一个页面实现两个zTree联动的方法
2017/12/20 Javascript
jQuery实现点击图标div循环放大缩小功能
2018/09/30 jQuery
如何提升vue.js中大型数据的性能
2019/06/21 Javascript
JS正则表达式验证端口范围(0-65535)
2020/01/06 Javascript
解决iView Table组件宽度只变大不变小的问题
2020/11/13 Javascript
详解JavaScript原型与原型链
2020/11/16 Javascript
详解Python 数据库的Connection、Cursor两大对象
2018/06/25 Python
详解Python下载图片并保存本地的两种方式
2019/05/15 Python
python3连接MySQL8.0的两种方式
2020/02/17 Python
python:批量统计xml中各类目标的数量案例
2020/03/10 Python
Tensorflow中的dropout的使用方法
2020/03/13 Python
Python实现Appium端口检测与释放的实现
2020/12/31 Python
python 实现的车牌识别项目
2021/01/25 Python
CSS3 简写animation
2012/05/10 HTML / CSS
CSS3新属性transition-property transform box-shadow实例学习
2013/06/06 HTML / CSS
CSS类名支持中文命名的示例
2014/04/04 HTML / CSS
美国面料纺织品商城:Fabric.com
2017/06/28 全球购物
The Athlete’s Foot新西兰:新西兰最大的运动鞋零售商
2019/12/23 全球购物
建筑工程管理专业自荐信范文
2013/12/28 职场文书
初中军训感想300字
2014/03/05 职场文书
年度考核自我鉴定
2014/03/19 职场文书
座谈会主持词
2014/03/20 职场文书
赔偿协议书范本
2014/09/12 职场文书
Html分层的box-shadow效果的示例代码
2021/03/30 HTML / CSS
jquery插件实现悬浮的菜单
2021/04/24 jQuery
python playwright 自动等待和断言详解
2021/11/27 Python