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 相关文章推荐
使用70行Python代码实现一个递归下降解析器的教程
Apr 17 Python
Python实现简单截取中文字符串的方法
Jun 15 Python
python安装Scrapy图文教程
Aug 14 Python
Python线程障碍对象Barrier原理详解
Dec 02 Python
python绘制彩虹图
Dec 16 Python
Pycharm最新激活码2019(推荐)
Dec 31 Python
Pyecharts绘制全球流向图的示例代码
Jan 08 Python
Python paramiko 模块浅谈与SSH主要功能模拟解析
Feb 29 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
Jun 30 Python
Python如何读写CSV文件
Aug 13 Python
python 检测图片是否有马赛克
Dec 01 Python
详解pandas中利用DataFrame对象的.loc[]、.iloc[]方法抽取数据
Dec 13 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
第七节 类的静态成员 [7]
2006/10/09 PHP
PHP中通过ADO调用Access数据库的方法测试不通过
2006/12/31 PHP
PHP 获取远程文件内容的函数代码
2010/03/24 PHP
php使用Jpgraph绘制柱形图的方法
2015/06/10 PHP
PHPExcel在linux环境下导出报500错误的解决方法
2017/01/26 PHP
PHP实现webshell扫描文件木马的方法
2017/07/31 PHP
php中加密解密DES类的简单使用方法示例
2020/03/26 PHP
用javascript获取textarea中的光标位置
2008/05/06 Javascript
jQuery 处理网页内容的实现代码
2010/02/15 Javascript
利用jQuery简单实现产品展示图片左右滚动功能(示例代码)
2014/01/02 Javascript
Jquery中巧用Ajax的beforeSend方法
2016/01/20 Javascript
jQuery插件 Jqplot图表实例
2016/06/18 Javascript
AngularJS入门教程之过滤器用法示例
2016/11/02 Javascript
node文件上传功能简易实现代码
2017/06/16 Javascript
vue debug 二种方法
2018/09/16 Javascript
详解vue项目中实现图片裁剪功能
2019/06/07 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
[02:37]2018DOTA2亚洲邀请赛赛前采访 VP.no[o]ne心中最强SOLO是谁
2018/04/04 DOTA
Python入门篇之数字
2014/10/20 Python
使用Python构建Hopfield网络的教程
2015/04/14 Python
详解tensorflow载入数据的三种方式
2018/04/24 Python
pygame游戏之旅 按钮上添加文字的方法
2018/11/21 Python
nohup后台启动Python脚本,log不刷新的解决方法
2019/01/14 Python
pyqt5 实现 下拉菜单 + 打开文件的示例代码
2019/06/20 Python
python用Tkinter做自己的中文代码编辑器
2020/09/07 Python
python 如何停止一个死循环的线程
2020/11/24 Python
纯html5+css3下拉导航菜单实现代码
2013/03/18 HTML / CSS
联想美国官方商城:Lenovo美国
2017/06/19 全球购物
机械专业毕业生自荐信
2013/11/02 职场文书
社区戒毒工作方案
2014/06/04 职场文书
理财学专业自荐书
2014/06/28 职场文书
2014学校领导四风问题对照检查材料思想汇报
2014/09/22 职场文书
党员自评材料范文
2014/12/17 职场文书
幼儿园端午节活动总结
2015/05/05 职场文书
重温入党誓词主持词
2015/06/29 职场文书
高三教师工作总结2015
2015/07/21 职场文书