难度: ★☆☆☆☆ 1星


这个网站的注册页面上有一个看上去很复杂的验证码,但是实际上是假的,让我们打开这个页面:

https://mail.wo.cn/register

输入完信息之后还需要搞一个滑动验证,得把滑块向右滑动,不过看上去也不是那么麻烦啊:

沃邮箱注册点选验证码(明文返回)_验证码

打开控制台,清空掉无关请求,然后再把上面的滑块向右滑动直到验证成功,观察到控制台上没有新的请求,这就有点诡异了:

沃邮箱注册点选验证码(明文返回)_验证码_02

这说明滑块验证码向右滑动这个只是前端的一个事件,不是真正的验证,然后滑到头之后出来一个看上去很吓人的验证码:

沃邮箱注册点选验证码(明文返回)_验证码_03

我们尝试选中验证码图片,观察一下这张图片是怎样的:

沃邮箱注册点选验证码(明文返回)_验证码_04

源码面板:

沃邮箱注册点选验证码(明文返回)_验证码_05

等等,好像有哪里不太对,选中的图片中的那个“早”字,它好像在源码面板直接显示出来了...这说明这个字一定是从哪里传输回页面的上的,我们只需要找到那个请求就好了。

仍然是把无关请求清空掉(上次清完之后好像还没有新的请求...),然后点击验证码上的刷新,从控制台的Network观察一下它的流程:

沃邮箱注册点选验证码(明文返回)_验证码_06

Network面板出现了几个新的请求:

沃邮箱注册点选验证码(明文返回)_验证码_07

先看第一个:

沃邮箱注册点选验证码(明文返回)_验证码_08

看上去像是一个请求验证码的操作,还带上了我刚刚注册时输入的手机号,然后再看看它的响应是什么,怎么是一坨文字,难道是我们想找的东西:

沃邮箱注册点选验证码(明文返回)_验证码_09

然后和页面上做对比,会发现好像randomChar好像就是那两行文本,而randomCode1和randomCode2就是让点选的字:

沃邮箱注册点选验证码(明文返回)_验证码_10

然后再看另外几个请求,这个请求貌似就是去根据之前注册的手机号生成验证码的,毕竟在页面上还要显示成图片的样子吓人:

沃邮箱注册点选验证码(明文返回)_验证码_11

这个是生成要点选的文字的,同理吓人:

沃邮箱注册点选验证码(明文返回)_验证码_12

然后再在页面上点选这两个文字,看下提交成功会是什么样子:

沃邮箱注册点选验证码(明文返回)_验证码_13

看下点选成功的网络请求是什么样子的:

沃邮箱注册点选验证码(明文返回)_验证码_14

然后在页面上点击“注册”按钮提交注册表单,结果弹出一个发短信验证码的弹窗:

沃邮箱注册点选验证码(明文返回)_验证码_15

先不管弹窗,先看下提交注册表单的网络请求:

沃邮箱注册点选验证码(明文返回)_验证码_16

然后回到网页,单击弹窗里的“获取短信校验码”按钮:

沃邮箱注册点选验证码(明文返回)_验证码_17

看下对应的网络请求:

沃邮箱注册点选验证码(明文返回)_验证码_18

和这个请求的响应:

沃邮箱注册点选验证码(明文返回)_验证码_19

至此整个过程就比较清晰了,我们只需要按下面的流程发送请求即可:

沃邮箱注册点选验证码(明文返回)_验证码_20

实现代码:

#!/usr/bin/env python3
# encoding: utf-8
"""
@author: CC11001100
"""

import logging

import requests

LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)

session = requests.session()


def register(phone_number, passwd):
    # 获取验证码
    response = very_code(phone_number)
    # 提交验证码
    response = check_very_code(response, phone_number)
    # 弹窗也要发请求啊
    h5_callback(phone_number, passwd)
    # 获取手机验证码
    order_meal(phone_number, passwd)


def order_meal(phone_number, passwd):
    url = "https://mail.wo.cn/orderMeal"
    # 注意同一个字段的参数名字与之前的几个接口不同,怪我自己瞎...
    # 难道是不同的人写的,如果是一个人写的哥们也太分裂了吧...
    data = {
        "phone": phone_number,
        "password": passwd,
        "productId": "8888888888"
    }
    response = session.post(url, data=data)
    logging.info(f"获取短信验证码结果: {response.text}")
    return response


def h5_callback(phone_number, passwd):
    url = "https://mail.wo.cn/h5Callback"
    data = {
        "userPhone": phone_number,
        "password": passwd,
        "productID": "8888888888"
    }
    headers = {
        # refer是必须带的
        "Referer": "https://mail.wo.cn/register",
    }
    response = session.post(url, headers=headers, data=data)
    logging.info(f"打开弹窗结果: {response.text}")
    return response


def very_code(phone_number):
    """
    请求验证码
    :param phone_number:
    :return: {'randomCode1': '此', 'randomCode2': '找', 'randomChar': '准背世风字此话离找没'}
    """
    url = "https://mail.wo.cn/veryCode"
    data = {
        "actionType": "veryCode",
        "user": phone_number,
        "domain": "wo.cn"
    }
    response = session.post(url, data=data)
    logging.info(f"请求到验证码: {response.text}")
    return response.json()


def check_very_code(very_code_response, phone_number):
    url = "https://mail.wo.cn/checkVeryCode"
    data = {
        "actionType": "checkVeryCode",
        "user": phone_number,
        "userCode": very_code_response["randomCode1"] + very_code_response["randomCode2"]
    }
    response = session.post(url, data=data)
    logging.info(f"提交验证码的结果: {response.text}")
    return response


if __name__ == "__main__":
    register("13791488888", "cC11001100")

运行结果:

沃邮箱注册点选验证码(明文返回)_验证码_21


仓库:

https://github.com/CC11001100/misc-crawler-public/tree/master/003-captcha/01-003-mail.wo.cn


请注意爬虫文章具有时效性,本文写于2020-11-6日。