关于腾讯微视频采集解决方案
Github 地址 点这里
前段时间看到一个关于微信数据采集的小项目,我感觉非常不错, 修改它做一些好玩的事,用来获取短视频平台的一些数据,
它很容易理解,也很容易进行修改,可以为以后其他爬虫提供思路。
首先确保你有一台或多台安卓 手机,使用adb 对手机进行模拟操作,我们可以使用代理拦截的方式进行获取数据 当然我们也可以使用其他的方式,多种多样的玩法或许很有成就感
关于adb 使用 可以 点这里
控制手机
from os import system
import random
import time
from threading import Thread
def connect_phone(func):
"""
装饰器负责每次命令前连接手机
:param func:
:return:
"""
def wrapper(*args, **kwargs):
system('adb connect ' + args[0].phone)
return func(*args, **kwargs)
return wrapper
class PhoneControl():
def __init__(self, phone):
"""
:param phone:adb 操作手机所需要的端口信息
"""
self.phone = phone
def get_phone(self):
"""
获取实例手机端口信息
"""
return self.phone
@connect_phone
def get_screen_cap(self, file_name='screen_cap'):
"""
获取截图
"""
system('adb -s ' + str(self.phone) + ' shell screencap -p /sdcard/' + file_name + '.png')
system('adb -s ' + str(self.phone) + ' pull /sdcard/' + file_name + '.png' + ' ./' + file_name + '.png')
return file_name + '.png'
@connect_phone
def input_tap(self, pos):
"""
点击屏幕
pos为一个区域的左上与右下坐标
如果事先已经随机化了pos可以只是一个点 随机点击一个位置是为防止被被认为是机器人
返回实际点击位置
"""
if len(pos) == 2:
_pos = pos
else:
_pos = (random.randint(pos[0], pos[2]), random.randint(pos[1], pos[3]))
command = r'adb -s ' + str(self.phone) + ' shell input tap {} {}'.format(_pos[0], _pos[1])
system(command)
return _pos
@connect_phone
def input_swipe(self, x1, x2):
"""
从一个位置滑动到另一位置
:param x1:起始坐标,屏幕左上角为原点
:param x2:终点坐标,屏幕左上角为原点
:return:[x1,x2]
"""
command = r'adb -s ' + str(self.phone) + ' shell input swipe {} {} {} {}'.format(x1[0], x1[1], x2[0], x2[1])
system(command)
return [x1, x2]
@connect_phone
def input_roll(self, dx=500, dy=0):
"""
拉动屏幕 向上拉动屏幕
:param dx:x方向速度
:param dy:y方向速度
:return:[dx, dy]
"""
command = r'adb -s ' + str(self.phone) + ' shell input roll {} {}'.format(dx, dy)
system(command)
return [dx, dy]
@connect_phone
def input_key_event(self, event_cmd):
"""
按键事件 比如home menue back volum_up volum_down等等 具体定义在配置文件中
:param event_cmd:事件ID
:return:event_cmd
"""
command = r'adb -s ' + str(self.phone) + ' shell input keyevent ' + event_cmd
system(command)
return event_cmd
@connect_phone
def input_text(self, text):
"""
输入文本信息 可能不支持中文输入
:param text:待输入的文本信息
:return:文本信息
"""
command = r'adb -s ' + str(self.phone) + ' shell input text {}'.format(text)
system(command)
return text
@connect_phone
def input_chn(self, text):
"""
支持中文 需要事先将ADB键盘设置为默认输入法而且打开软键盘
:param text:待输入的文本信息
:return:文本信息
"""
# command = r'adb -s '+str(self.phone)+' shell am broadcast -a ADB_INPUT_TEXT --es msg {}'.format(text)
command = r'adb -s ' + str(self.phone) + ' shell am broadcast -a ADB_INPUT_TEXT --es msg {}'.format(text)
system(command)
return text
class OperateAllPhone():
"""
同时控制给定abd端口的所有手机 请确保手机初始界面一致
"""
def __init__(self, phone_list):
"""
:param phone_list:
"""
self.phone_list = phone_list
self.pcs = []
for ap in self.phone_list:
self.pcs.append(PhoneControl(ap))
def key(self, event):
self.operate_all("input_key_event", (event,))
def text(self, str_data):
self.operate_all("input_chn", (str_data,))
def swap(self, x1, x2):
self.operate_all("input_swipe", (x1, x2))
def roll(self, dx, dy):
self.operate_all("input_roll", (dx, dy))
def tap(self, pos):
self.operate_all("input_tap", (pos,))
def operate_all(self, operation, args):
"""
:param operation: PhoneControl实例方法字符串名称
:param args:tuple格式参数
:return:
"""
_tasks = []
for pc in self.pcs:
_tasks.append(Thread(target=pc.__getattribute__(operation), args=args))
for t in _tasks:
t.start()
for t in _tasks:
t.join()
return operation
if __name__ == '__main__':
p = PhoneControl('xxx')
for i in range(20):
p.input_swipe([761, 1390], [806, 999])
time.sleep(0.8)
2 进行某些必须操作, 比如模拟点击加载, 下拉刷新,左右滑动 等
3 如果使用代理拦截 我们这里使用mitmproxy, 可以将拦截到的代理发送到redis或者其地方,也可以使用粘贴剪切板方式,明显代理拦截要更为快捷。
import mitmproxy.http
from mitmproxy import ctx
class Counter(object):
def __init__(self):
self.num = 0
self.url_list = list()
def request(self, flow: mitmproxy.http.HTTPFlow):
if 'http://v.weishi.qq.com/shg' in flow.request.pretty_url:
print('+'*20)
u = flow.request.pretty_url
print('+'*20)
with open('u_list.txt', 'a') as f:
f.write(str(u) + '\n')
addons = [
Counter()
]
4 这样就可以拦截到需要的请求,保存到了本地文件
5 另外 还有一种方式可以使用 因为代理拦截方式有时候并不那么完美,可以使用复制剪切板的方式