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的爬虫包Beautiful Soup中用正则表达式来搜索
Jan 20 Python
Python实现中文数字转换为阿拉伯数字的方法示例
May 26 Python
Python cookbook(数据结构与算法)根据字段将记录分组操作示例
Mar 19 Python
django 使用 request 获取浏览器发送的参数示例代码
Jun 11 Python
python实现多人聊天室
Mar 31 Python
python lxml中etree的简单应用
May 10 Python
python脚本开机自启的实现方法
Jun 28 Python
Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签
Dec 04 Python
pytorch逐元素比较tensor大小实例
Jan 03 Python
DjangoWeb使用Datatable进行后端分页的实现
May 18 Python
python3操作redis实现List列表实例
Aug 04 Python
python 单机五子棋对战游戏
Apr 28 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
锁定年轻人的双倍活力 星巴克推出星倍醇即饮浓咖啡
2021/03/03 咖啡文化
php 全局变量范围分析
2009/08/07 PHP
PHP strncasecmp字符串比较的小技巧
2011/01/04 PHP
Zend studio文件注释模板设置方法
2013/09/29 PHP
PHP获取一个字符串中间一部分字符的方法
2014/08/19 PHP
php使用gzip压缩传输js和css文件的方法
2015/07/29 PHP
PHP更安全的密码加密机制Bcrypt详解
2017/06/18 PHP
PHP实现文件上传后台处理脚本
2020/03/04 PHP
Aster vs Newbee BO5 第一场2.19
2021/03/10 DOTA
javascript+dom树型菜单类,希望朋友们一起进步
2007/05/03 Javascript
解决jquery异步按一定的时间间隔刷新问题
2012/12/10 Javascript
jQuery插件实现静态HTML验证码校验
2015/11/06 Javascript
利用jquery给指定的table动态添加一行、删除一行的方法
2016/10/12 Javascript
详解ECharts使用心得总结
2016/12/06 Javascript
基于 Vue 实现一个酷炫的 menu插件
2017/11/14 Javascript
浅析JS中什么是自定义react数据验证组件
2018/10/19 Javascript
Vue组件Draggable实现拖拽功能
2018/12/01 Javascript
微信小程序实现订单倒计时
2020/11/01 Javascript
JavaScript实现公告栏上下滚动效果
2020/03/13 Javascript
原生js滑动轮播封装
2020/07/31 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
2020/12/16 Javascript
Python使用pylab库实现画线功能的方法详解
2017/06/08 Python
django 自定义过滤器的实现
2019/02/26 Python
Python分析彩票记录并预测中奖号码过程详解
2019/07/09 Python
python进阶之自定义可迭代的类
2019/08/20 Python
tensorflow ckpt模型和pb模型获取节点名称,及ckpt转pb模型实例
2020/01/21 Python
简单了解python shutil模块原理及使用方法
2020/04/28 Python
python小白切忌乱用表达式
2020/05/29 Python
什么是Python中的顺序表
2020/06/02 Python
利用django创建一个简易的博客网站的示例
2020/09/29 Python
护理毕业生自荐信范文
2013/12/22 职场文书
消防器材管理制度
2014/01/28 职场文书
《孔子游春》教学反思
2014/02/25 职场文书
骨干教师考核方案
2014/05/09 职场文书
2015年学校德育工作总结
2015/04/22 职场文书
庭外和解协议书
2016/03/23 职场文书