zoukankan      html  css  js  c++  java
  • 利用爬虫模拟网页微信wechat

    利用爬虫模拟网页微信wechat

     

    1.登录页面,显示二维码

    当我们打开网页微信时,会看到一个用于扫码登录的二维码,所以我们要模拟该页面给我们的页面也弄一个二维码

    通过查看网页代码我们发现,这个二维码的标签为

    这个src属性的最后一段每次访问都是不同的,我们发现每次访问该页面时,会向后端发送请求获得这个随机字符串

    这个请求的结果为

    所以该请求获取的结果就是我们想要的随机字符串,那么我们也可以向这个url发送请求,获取随机字符串,并利用随机字符串拼接地址获取二维码图片

    复制代码
    from flask import Flask, request, render_template, session
    import time
    import requests
    import re
    app = Flask(__name__)
    app.debug = True
    app.secret_key = 'ksjgs'
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            ctime = str(int(time.time() * 1000))  # url最后的内容其实是时间戳经过处理的结果
            qcode_url = 'https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={}'.format(ctime)
            ret = requests.get(qcode_url)
            qcode = re.findall('uuid = "(.*)";', ret.text)[0]
            session['qcode'] = qcode
            return render_template('login.html', qcode=qcode)
        else:
            pass
    
    if __name__ == '__main__':
        app.run()
    复制代码

    login页面

    复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>微信登录</title>
    </head>
    <body>
    <h1>微信登录</h1>
    <img src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
    <script src="/static/jquery-3.2.1.min.js"></script>
    
    </body>
    </html>
    复制代码

    这样,我们访问时就能看到二维码了

    扫码后二维码变成用户头像

    看到二维码后如果我们进行了扫码,那么页面上的二维码会立刻变成用户的头像,但是此时我们并没有看到页面向后端发送请求,为什么后端能让前端的页面发生变化呢,我们通过浏览器的network选项发现,其实当页面加载完成后,浏览器会不停的向后端的一个url发送

    请求,这个请求发送到后端后就被夯住了,这个时间在25秒左右,如果没有人扫码,那么请求会结束,浏览器继续发送,如果有人扫码了,那么后端会立刻向浏览器返回相关信息,浏览器就可以将页面的二维码改变为用户的头像了,这种持续发送请求的方式称为长轮询

    我们在页面加载完成后也模拟这个长轮询

    login页面

    复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>微信登录</title>
    </head>
    <body>
    <h1>微信登录</h1>
    <img src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
        $(function () {
            check_login()
        });
    
        function check_login() {
            $.ajax({
                url: '/check_login',
                type: 'GET',
                dataType: 'JSON',
                success:function (arg) {
                    if (arg.code === 201){
                        $('img').attr('src', arg.src);
                        check_login()
                    } else if(arg.code === 200){
                        location.href = '/index'
                    }else{
                        check_login()
                    }
                }
            })
        }
    </script>
    </body>
    </html>
    复制代码

    前端页面加载完成后就开始向后端发送ajax长轮询,根据后端返回的内容判断是否继续发送轮询还是进行跳转,如果有人扫码了,那么就将扫码人的头像替换页面上的二维码,并继续轮询,直到扫码人点击确认,则进行跳转,没人扫码则一直进行长轮询

    后端

    复制代码
    from flask import Flask, request, render_template, session, jsonify
    import time
    import requests
    import re
    from bs4 import BeautifulSoup
    
    app = Flask(__name__)
    app.debug = True
    app.secret_key = 'ksjgs'
    
    
    def xml_parser(text):
        """
        <error>
        <ret>0</ret><
        message></message>
        <skey>@crypt_ef73b06b_bd2d7a9918de33c9fc59b3b518a5314f</skey>
        <wxsid>5gfJFQAju+rnuD3t</wxsid><
        wxuin>2507632864</wxuin>
        <pass_ticket>n3hBG1Aky%2FORERALnTUhkjRrAaho%2BX6vu8%2B9Z3gPrsmnWmKqs5a%2BFe%2FehjeweCeP</pass_ticket>
        <isgrayscale>1</isgrayscale>
        </error> 
        """
        dic = {}
        soup = BeautifulSoup(text, 'html.parser')
        div = soup.find(name='error')
        for item in div.find_all(recursive=False):
            dic[item.name] = item.text
        return dic
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            ctime = str(int(time.time() * 1000))  # url最后的内容其实是时间戳经过处理的结果
            qcode_url = 'https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={}'.format(
                ctime)
            ret = requests.get(qcode_url)
            qcode = re.findall('uuid = "(.*)";', ret.text)[0]
            session['qcode'] = qcode
            return render_template('login.html', qcode=qcode)
        else:
            pass
    
    
    @app.route('/check_login')
    def check_login():
        ctime = str(int(time.time() * 1000))
        qcode = session.get('qcode')
        check_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={}&tip=0&r=-1052355888&_={}'.format(
            qcode, ctime)
        ret = requests.get(check_url)
        response = {'code': 408}  # 如果没人扫码,则返回的code为408
        if 'code=201' in ret.text:  # 如果有人扫码了,则会返回201,并且会返回用户的头像的src
            response['code'] = 201
            response['src'] = re.findall("userAvatar = '(.*)';", ret.text)[0]
        elif 'code=200' in ret.text:  # 有人扫码后前端页面仍然会发送长轮询,直到扫码的人点击确认登录,会返回200
            redirect_uri = re.findall('redirect_uri="(.*)";', ret.text)[0]  # 此时会返回跳转地址
            # 向redirect_uri地址发送请求,获取凭证相关信息
            redirect_uri = redirect_uri + "&fun=new&version=v2"  # 这个跳转地址并不全,我们需要自己补充
            ticket_ret = requests.get(redirect_uri)  # 向跳转地址发送请求,获取登录凭证
            ticket_dict = xml_parser(ticket_ret.text)  # 这个登录凭证是一个xml的格式,我们通过一个函数将他转换成字典
            session['ticket_dict'] = ticket_dict  # 将登录凭证存入session,方便后面使用
            response['code'] = 200
        return jsonify(response)
    
    
    @app.route('/index')
    def index():
        return '登录成功'
    
    if __name__ == '__main__':
        app.run()
    复制代码

    获取用户信息

    当确认登录后,会返回跳转地址,浏览器会向这个跳转地址发送get请求,获取一个凭证(类似于cookie,xml格式),获取这个凭证后,浏览器会接着发送一个post请求,请求内容就是凭证内的相关内容,这个post请求就能获取用户的信息,最近联系人等信息

    我们这里通过index函数来发送这个post请求

    复制代码
    @app.route('/index')
    def index():
        """
        用户数据的初始化
        https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1039465096&lang=zh_CN&pass_ticket=q9TOX4RI4VmNiHXW9dUUl1oMzoQK2X2f3H3kn0VYm5YGNwUMO2THYMznv8DSXqp0
    
        :return:
        """
        ticket_dict = session.get('ticket_dict')
        init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1039465096&lang=zh_CN&pass_ticket={0}".format(ticket_dict.get('pass_ticket'))
    
        data_dict = {
            "BaseRequest":{
                "DeviceID":"e750865687999321",
                "Sid":ticket_dict.get('wxsid'),
                "Uin":ticket_dict.get('wxuin'),
                "Skey":ticket_dict.get('skey'),
            }
        }
    
        init_ret = requests.post(
            url=init_url,
            json=data_dict
        )
        init_ret.encoding = 'utf-8'
        user_dict = init_ret.json()
        print(user_dict)
        # for user in user_dict['ContactList']:
        #     print(user.get('NickName'))
    
        return render_template('index.html',user_dict=user_dict)
    复制代码

    首先从session中获取我们处理后得到的凭证字典,然后发送post请求,这里发送的数据为json格式,post请求的返回内容就是用户相关数据的字典,我们可以通过ret.json()直接获取这个字典(相当于经过json.loads),然后将相关的内容渲染到页面上

    index页面

    复制代码
    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
        <h1>欢迎登录:{{user_dict.User.NickName}}</h1>
        <h3>最近联系人</h3>
        <ul>
            {% for user in user_dict.ContactList%}
            <li>{{user.NickName}}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    复制代码
  • 相关阅读:
    struts2国际化
    Struts2运行机制
    HelloStruts2
    iOS流布局UICollectionView系列七——三维中的球型布局
    iOS- UITextView与键盘回收与键盘遮挡输入框
    web 网页截取图片
    iOS 平台如何使用 TestFlight 进行 Beta 测试
    Ubuntu shortcuts
    ubuntu study
    ios 即时通讯 xmpp
  • 原文地址:https://www.cnblogs.com/xyhh/p/10860564.html
Copyright © 2011-2022 走看看