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 相关文章推荐
Python2.x和3.x下maketrans与translate函数使用上的不同
Apr 13 Python
举例讲解Python中的算数运算符的用法
May 13 Python
Python中创建字典的几种方法总结(推荐)
Apr 27 Python
Python语言描述随机梯度下降法
Jan 04 Python
python3使用腾讯企业邮箱发送邮件的实例
Jun 28 Python
Python 的AES加密与解密实现
Jul 09 Python
python 导入数据及作图的实现
Dec 03 Python
Python列表切片常用操作实例解析
Dec 16 Python
python sklearn包——混淆矩阵、分类报告等自动生成方式
Feb 28 Python
Python计算矩阵的和积的实例详解
Sep 10 Python
pycharm配置安装autopep8自动规范代码的实现
Mar 02 Python
如何获取numpy array前N个最大值
May 14 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脚本的10个技巧(6)
2006/10/09 PHP
关于js与php互相传值的介绍
2013/06/25 PHP
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
jQuery获取选中内容及设置元素属性的方法
2014/07/09 Javascript
Windows系统中安装nodejs图文教程
2015/02/28 NodeJs
javascript数组克隆简单实现方法
2015/12/16 Javascript
Bootstrap精简教程中秋大放送
2016/09/15 Javascript
Angularjs 设置全局变量的方法总结
2016/10/20 Javascript
Javascript中关于Array.filter()的妙用详解
2016/12/04 Javascript
Jqprint实现页面打印
2017/01/06 Javascript
JS实现针对给定时间的倒计时功能示例
2017/04/11 Javascript
Vue2.0 UI框架ElementUI使用方法详解
2017/04/14 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
2017/05/10 Javascript
javascript回调函数详解
2018/02/06 Javascript
原生JS实现轮播图效果
2018/10/12 Javascript
解决Vue中 父子传值 数据丢失问题
2019/08/27 Javascript
python实现连接mongodb的方法
2015/05/08 Python
浅谈python配置与使用OpenCV踩的一些坑
2018/04/02 Python
python3 下载网络图片代码实例
2019/08/27 Python
nginx搭建基于python的web环境的实现步骤
2020/01/03 Python
python如何提取英语pdf内容并翻译
2020/03/03 Python
浅谈django channels 路由误导
2020/05/28 Python
opencv 查找连通区域 最大面积实例
2020/06/04 Python
Python利用imshow制作自定义渐变填充柱状图(colorbar)
2020/12/10 Python
Django+Django-Celery+Celery的整合实战
2021/01/20 Python
利用Python批量识别电子账单数据的方法
2021/02/08 Python
STAY JAPAN台湾:预订日本民宿
2018/07/22 全球购物
英国在线药房:Chemist.co.uk
2019/03/26 全球购物
Pandora德国官网:购买潘多拉手链、戒指、项链和耳环
2020/02/20 全球购物
C#中有没有运算符重载?能否使用指针?
2014/05/05 面试题
大学生先进事迹材料
2014/02/16 职场文书
奠基仪式主持词
2014/03/20 职场文书
《荷花》教学反思
2014/04/16 职场文书
干部作风整顿自我剖析材料和整改措施
2014/09/18 职场文书
遗失说明具结保证书
2015/02/26 职场文书
详解PHP Swoole与TCP三次握手
2021/05/27 PHP