Python多线程豆瓣影评API接口爬虫
爬虫库
使用简单的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多线程豆瓣影评API接口爬虫的更多相关文章
- 用Python调用华为云API接口发短信
[摘要] 用Python调用华为云API接口实现发短信,当然能给调用发短信接口前提条件是通过企业实名认证,而且有一个通过审核的短信签名,话不多说,showcode #!/usr/bin/python3 ...
- python使用zabbix的API接口
一.实验环境 python3.6.6 zabbix 3.0.9 二.实验目的 了解Zabbix的API接口格式 通过python实现登陆zabbix服务,获得登陆token 通过python检索zab ...
- python访问cloudstack的api接口
1.CloudStack API 如同 AWS API 一样,CloudStack API 也是基于 Web Service,可以使用任何一种支持 HTTP 调用的语言(例如 Java,python, ...
- Java多线程:实现API接口创建线程方式详解
先看例子: /**实现Runnable接口创建线程步骤: * 1.创建一个实现Runnable接口的类 * 2.重写Runnable类中抽象的run()方法 * 3.创建实现类的对象 * 4.声明Th ...
- 简单实现Python调用有道API接口(最新的)
# ''' # Created on 2018-5-26 # # @author: yaoshuangqi # ''' import urllib.request import urllib.pars ...
- Python实现简单的API接口
get方法 代码实现 # coding:utf-8 import json from urlparse import parse_qs from wsgiref.simple_ ...
- 利用python多线程模块实现模拟接口并发
import requestsimport jsonimport threadingimport timeimport uuid class postrequests(): def __init__( ...
- python 多线程,多进程,高效爬虫
1.多线程from concurrent.futures import ThreadPoolExecutor import requests def fetch_async(url): respons ...
- 使用Python解析豆瓣上Json格式数据
现在的API接口多为xml或json,json解析更简洁相对xml来说 以豆瓣的API接口为例,解析返回的json数据: https://api.douban.com/v2/book/1220562 ...
随机推荐
- 洛谷P3239 [HNOI2015]亚瑟王(期望dp)
传送门 stdcall大佬好强 期望的姿势不是很高……据大佬说期望有一个线性性质,也就是说可以把每一张牌的期望伤害算出来然后再加起来就是总的期望伤害 因为每一张牌只能用一次,我们设$dp[i]$表示第 ...
- [Swift通天遁地]一、超级工具-(2)制作美观大方的环形进度条
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- centos7开启路由转发
centos7开启路由转发 编辑/etc/sysctl.conf,添加一下内容. vim /etc/sysctl.conf net.ipv4.ip_forward=1 net.ipv4.conf.al ...
- 题解报告:hdu 2544 最短路
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t ...
- ASP.NET中图片验证码与js获取验证码的值
现在的程序中,为了防止用户恶意点击,我们一般都会加上验证,现在比较普遍的是加上图片验证码或者手机短信验证.验证码一般都是防机器不防人,有效的防止了恶意点击. 那么在webform中如何生成动态的图片验 ...
- vue组件中—bus总线事件回调函数多次执行的问题
在利用vue组件进行事件监听时发现,如果对N个vue组件实例的bus总线绑定同一事件的回调函数,触发任意组件的对应事件,回调函数至少会被执行N次,这是为什么呢? 为此,调研了普通对象的事件绑定和触发实 ...
- 摘:关于php调用.net的web service 踩过的坑
文档地址:http://www.cnblogs.com/wyycc/p/6722701.html
- Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser]
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- iOS 对overflow:scroll使用
让子标签的高度在初始化的时候就比父标签大,可以设置height: 101%:这样就出发了内置的scrollview的滚动. -webkit-overflow-scrolling:touch;可以让滚动 ...
- webstorm里直接调用命令行
写代码写到一半要切换窗口出去敲命令行?webstorm的external tools可以帮你省下一点时间 举例说明,比如我要直接使用npm: ctrl+alt+s打开setting菜单,找到exter ...