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之有容乃大的list(1)
Sep 14 Python
Python实现的彩票机选器实例
Jun 17 Python
Python一句代码实现找出所有水仙花数的方法
Nov 13 Python
Numpy截取指定范围内的数据方法
Nov 14 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
Dec 12 Python
python模糊图片过滤的方法
Dec 14 Python
解决python super()调用多重继承函数的问题
Jun 26 Python
python opencv实现证件照换底功能
Aug 19 Python
python之生成多层json结构的实现
Feb 27 Python
使用Python+selenium实现第一个自动化测试脚本
Mar 17 Python
python进行二次方程式计算的实例讲解
Dec 06 Python
再谈python_tkinter弹出对话框创建
Mar 20 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数据库操作类(改自discuz)
2010/07/03 PHP
TP5框架实现自定义分页样式的方法示例
2020/04/05 PHP
基于Jquery的开发个代阴影的对话框效果代码
2011/07/28 Javascript
JSON语法五大要素图文介绍
2012/12/04 Javascript
jQuery弹出层始终垂直居中相对于屏幕或当前窗口
2013/04/01 Javascript
jQuery实现购物车多物品数量的加减+总价计算
2014/06/06 Javascript
jquery学习总结(超级详细)
2014/09/04 Javascript
jQuery中[attribute*=value]选择器用法实例
2014/12/31 Javascript
JavaScript设置获取和设置属性的方法
2015/03/04 Javascript
JavaScript实现向右伸出的多级网页菜单效果
2015/08/25 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
2016/01/06 Javascript
基于JavaScript实现通用tab选项卡(通用性强)
2016/01/07 Javascript
JS获取字符串实际长度(包含汉字)的简单方法
2016/08/11 Javascript
如何用JS/HTML将时间戳转换为“xx天前”的形式
2017/02/06 Javascript
JS简单判断函数是否存在的方法
2017/02/13 Javascript
使用vue构建一个上传图片表单
2017/07/04 Javascript
EasyUI在Panel上动态添加LinkButton按钮
2017/08/11 Javascript
jQuery 操作 HTML 元素和属性的方法
2018/11/12 jQuery
详解写好JS条件语句的5条守则
2019/02/28 Javascript
layui use 定义js外部引用函数的方法
2019/09/26 Javascript
用javascript实现倒计时效果
2021/02/09 Javascript
如何解决django配置settings时遇到Could not import settings 'conf.local'
2014/11/18 Python
使用Anaconda3建立虚拟独立的python2.7环境方法
2018/06/11 Python
python中的decorator的作用详解
2018/07/26 Python
python对XML文件的操作实现代码
2020/03/27 Python
Pandas读取csv时如何设置列名
2020/06/02 Python
Django 实现图片上传和下载功能
2020/12/31 Python
需要知道的CSS3动画技术
2010/01/01 HTML / CSS
精彩自我鉴定
2014/01/16 职场文书
学校机关党总支领导班子整改工作方案
2014/10/26 职场文书
督导岗位职责范本
2015/04/10 职场文书
小时代观后感
2015/06/10 职场文书
借钱欠条怎么写
2015/07/03 职场文书
Android基于Fresco实现圆角和圆形图片
2022/04/01 Java/Android
MSSQL基本语法操作
2022/04/11 SQL Server
Redis特殊数据类型HyperLogLog基数统计算法讲解
2022/06/01 Redis