最近朋友想让我帮忙把抖音的主播都爬出来。网上看了一些教程,大部分都是爬视频的。没有找到现成的爬所有主播的。所以参考了很多教程,自己写了一个专门爬主播数据的爬虫。系统是Windows 10,时间2021年1月12号。用这种方法略做修改基本可以爬取抖音所有数据,有兴趣的欢迎交流。
必备
按需下载
代理服务器端口:第一步中-p后自己设置的端口,这里是8888
填完后点击保存
在path中加入下面三个环境变量,主要是为了在command命令行中使用adb
打开新的命令行工具,输入adb,看是否能识别adb命令, 如果不能识别,那么是环境变量配置错误,确保path中ANDROID_HOME下的platform-tools下面有adb.exe
点击"Edit Configurations"
填入Android SDK和JDK的安装目录,然后“Save and Restart”
Appium重启后,点击“Start Server v1.19.1”, 如果提示端口被占用,改成其他端口,我使用的是47233
点击右上角的第一个按钮“Start Inspector Session”, 打开新的窗口
在"Desired Capabilities"下面添加配置,然后保存
点击“Start Session”
确保mimtproxy开启,git运行“mitmweb -p 8888”,确保网易mumu开启,并且连接成功“adb devices”中能看到。
如果提示证书错误,那么需要安装证书,网上安装证书教程如下,但是我一直下载不成功,所以直接下载的windows版证书,双击安装,也能正常使用。
打开桌面上的浏览器,地址栏输入“mitm.it”
下载完在桌面上可以看到“抖音”
页面显示的就是抖音中的主播
这时候网址重定向了,变成“https://webcast.amemv.com/webcast/reflow/6916700381529049859?utm_source=copy&utm_campaign=client_share&utm_medium=android&share_app_name=douyin”
可以看到这个地址中有一串长数字,其他应该都是常量,不变的,复制这串长数字6916700381529049859,回到mitmproxy打开的地址,ctrl+F,搜索,如果搜不到,上下滑动页面,会看到很多地方都有这串数字
选中第一个,在右侧request会看到完整地址:
保留这个完整地址
再回到刚才打开的抖音分享页面,右键-》查看网页源代码
将源代码复制到其他编辑器里,我复制到记事本里
在记事本里,会发现一段script里包含了主播所有的信息,这就是我们要爬取的信息。
import urllib.parse as urlparse
from urllib.parse import parse_qs
def response(flow):
global idx
url_prefix = 'https://webcast.amemv.com/webcast/gift/list/'
if flow.request.pretty_url.startswith(url_prefix):
url = flow.request.pretty_url
save_room_id(url)
def save_room_id(url):
try:
parsed = urlparse.urlparse(url)
room_id = parse_qs(parsed.query)['room_id']
with open('rooms.txt', 'a') as f:
for data in room_id:
f.write(data)
f.write('\
')
except:
print('error')
这段脚本会获取抖音中主播的room_id,然后保存到一个txt文件中
在git中,先cd到脚本所在的文件夹,然后输入“mitmdump -s get_user.py -p 8888”
这时如果滑动抖音,就可以获取当前主播的room_id,并保存
现在用appium实现自动滑屏
在appium中点击控件会在右侧显示控件id
抖音做了一些反爬虫设计,用appium打开抖音时,会出现一些授权窗口,我是出现了三个,所以需要先授权
授权完成之后,点击“直播”,然后每秒滑屏一次,代码如下
# -*- coding: utf-8 -*-
from appium import webdriver
from time import sleep
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
i=0
class DouYin(object):
def __init__(self):
# self.init_file()
self.desired_caps={
'platformName' : 'Android',
'platformVersion' : '6.0.1',
'deviceName' : '127.0.0.1:7555',
'appPackage' : 'com.ss.android.ugc.aweme',
'appActivity' : '.main.MainActivity'}
self.driver=webdriver.Remote('http://localhost:47233/wd/hub', self.desired_caps)
self.wait=WebDriverWait(self.driver, 60)
self.get_permission()
self.error_times=0
# self.init_file()
def swipe_up(self):
self.driver.swipe(373, 1029, 373, 387)
sleep(1)
# self.driver.tap([(385, 471)])
def zhibo(self):
self.driver.tap([(45, 80)], 500)
sleep(3)
def get_permission(self):
try:
allow=self.wait.until(
EC.presence_of_element_located((By.ID, 'com.ss.android.ugc.aweme:id/aps')))
if allow is not None:
allow.click()
allow=self.wait.until(
EC.presence_of_element_located((By.ID, 'com.android.packageinstaller:id/permission_deny_button')))
if allow is not None:
allow.click()
allow=self.wait.until(
EC.presence_of_element_located((By.ID, 'com.android.packageinstaller:id/permission_deny_button')))
if allow is not None:
allow.click()
sleep(10)
self.swipe_up()
self.zhibo()
except Exception as ex:
print(ex)
pass
def click_up(self):
ups_no=0
while True:
global i
try:
self.swipe_up()
i +=1
print(str(i))
except Exception as err:
print(err)
self.error_times +=1
if self.error_times < 5:
continue
else:
raise Exception('Error happens 5 times, restart')
def close_app(self):
self.driver.close_app()
def run(self):
self.click_up()
# self.close_app()
if __name__=='__main__':
while True:
try:
douyin=DouYin()
douyin.run()
except Exception as error:
print(error)
这是自动爬取效果视频,我的电脑比较卡,实际滑屏时间要多于1秒
这段代码有几个小问题,还没解决
1. 抖音出现更新提示,运行一段时间会出现
2. 抖音运行一段时间会重启,重启后python仍然以为在直播,所以继续滑动,但是目前其实在推荐
保存的主播room_id,可以用python脚本来获取主播详细信息并保存,这一步按需保存自己需要的信息,代码如下
import requests
import json
import csv
from bs4 import BeautifulSoup
import re
import os
csv_file='douyin.csv'
csv_columns=['name', 'douyin_id', 'gender','followers','description', 'avatar']
def save():
init_file()
with open('rooms.txt','r') as txt_file:
rooms=txt_file.read().split('\
')
for room in rooms:
save_one(room)
def save_one(room_id):
url='https://webcast.amemv.com/webcast/reflow/' + room_id + '?utm_source=copy&utm_campaign=client_share&utm_medium=android&share_app_name=douyin'
headers={
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36',
}
response=requests.get(url, headers=headers).text
soup=BeautifulSoup(response)
a=soup.find_all('script')
for t in a:
if 'owner_user_id' in str(t):
m=re.search('\\{.*\\}', str(t))
j=m.group(0)
j=json.loads(j)
user=j['/webcast/reflow/:id']['room']['owner']
save_ups(user)
user=json.dumps(user)
with open(f'user.json', 'a', encoding='utf-8-sig') as js:
js.write(user)
js.write('\
')
break
def init_file():
try:
if os.path.exists(csv_file):
return
with open(csv_file, 'w',encoding='utf-8-sig') as csvfile:
writer=csv.DictWriter(csvfile, fieldnames=csv_columns, delimiter=',', lineterminator='\
')
writer.writeheader()
except IOError as err:
print(err)
def save_ups(user):
up=dict()
up['name']=user['nickname']
up['douyin_id']=user['display_id']+'\ '
up['gender']='女' if user['gender']==2 else '男'
up['description']=user['signature']
up['followers']=user['follow_info']['follower_count']
up['avatar']=user['avatar_thumb']['url_list'][0]
with open(csv_file, 'a', encoding='utf-8-sig') as douyin:
writer=csv.DictWriter(douyin, fieldnames=csv_columns, delimiter=',', lineterminator='\
')
writer.writerow(up)
这是爬取的数据: