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实现图片滑动式验证识别方法
Nov 09 Python
pandas 实现将重复表格去重,并重新转换为表格的方法
Apr 18 Python
Python多进程与服务器并发原理及用法实例分析
Aug 21 Python
简单谈谈python基本数据类型
Sep 26 Python
python语言基本语句用法总结
Jun 11 Python
django项目中使用手机号登录的实例代码
Aug 15 Python
Python实现线性插值和三次样条插值的示例代码
Nov 13 Python
使用PyTorch实现MNIST手写体识别代码
Jan 18 Python
新建文件时Pycharm中自动设置头部模板信息的方法
Apr 17 Python
150行python代码实现贪吃蛇游戏
Apr 24 Python
如何用python反转图片,视频
Apr 24 Python
详解Python中的for循环
Apr 30 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计算当前坐标3公里内4个角落的最大最小经纬度实例
2016/02/26 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
JavaScript中Object和Function的关系小结
2009/09/26 Javascript
Js 随机数产生6位数字
2010/05/13 Javascript
JS小功能(button选择颜色)简单实例
2013/11/29 Javascript
js控制当再次点击按钮时的间隔时间
2014/06/03 Javascript
如何书写高质量jQuery代码(使用jquery性能问题)
2014/06/30 Javascript
Visual Studio中js调试的方法图解
2014/06/30 Javascript
创建、调用JavaScript对象的方法集锦
2014/12/24 Javascript
微信小程序 高德地图SDK详解及简单实例(源码下载)
2017/01/11 Javascript
Vuex之理解Store的用法
2017/04/19 Javascript
Vue通过ref父子组件拿值方法
2018/09/12 Javascript
js for终止循环 跳出多层循环
2018/10/04 Javascript
详解如何在vscode里面调试js和node.js的方法步骤
2018/12/24 Javascript
研究Python的ORM框架中的SQLAlchemy库的映射关系
2015/04/25 Python
Python编程中的文件读写及相关的文件对象方法讲解
2016/01/19 Python
Python 3.x 安装opencv+opencv_contrib的操作方法
2018/04/02 Python
详解Python 数据库的Connection、Cursor两大对象
2018/06/25 Python
Python异常模块traceback用法实例分析
2019/10/22 Python
Python lxml模块的基本使用方法分析
2019/12/21 Python
Python函数的定义方式与函数参数问题实例分析
2019/12/26 Python
Python抓包程序mitmproxy安装和使用过程图解
2020/03/02 Python
html5使用canvas画三角形
2014/12/15 HTML / CSS
美国儿童运动鞋和服装零售商:Kids Foot Locker
2017/08/05 全球购物
几道Java和数据库的面试题
2013/05/30 面试题
会计主管岗位职责范文
2013/11/08 职场文书
《学会合作》教学反思
2014/04/12 职场文书
创先争优标语
2014/06/27 职场文书
驾驶员安全责任书范本
2014/07/24 职场文书
农林经济管理专业自荐信
2014/09/01 职场文书
2014年大学生工作总结
2014/11/20 职场文书
大学生社会实践活动总结报告
2015/05/06 职场文书
小学运动会加油词
2015/07/18 职场文书
MySQL如何解决幻读问题
2021/08/07 MySQL
SpringBoot+Redis实现布隆过滤器的示例代码
2022/03/17 Java/Android
【海涛DOTA解说】EVE女子战队独家录像加ZSMJ神牛两连发
2022/04/01 DOTA