Article | xiao-fei li \

Source: Python Technology “ID: pythonall”

Last time I wrote how to make an appointment for a child’s equestrian course, see here Python appointment [1]. I wanted to make an appointment once and for all, but the good times didn’t last long. The appointment system was upgraded, and the service provider was changed, from the previous H5 application of the public account to a small program

He met a father who was a programmer? I can do this. Let’s do it

The difference between applets

Different from accessing H5, the small program is equivalent to an APP. The operations on it are encapsulated by wechat, so the request link and data cannot be directly obtained, and the returned data cannot be obtained either

Like an app, its requests are built into the app

In this case, you need to use a packet capture tool, such as Charles

The principle is that when a small program or APP sends a request as a proxy for the request, the request is first sent to the proxy, and then the proxy sends the request to the server, and the return process is the same

This is also known as a man-in-the-middle attack

Man-in-the-middle attack

If you want to get a specific request from an applet or app, you need to let the agent get the request and the corresponding data in this way

How do you play it? Directly refer to the Charles tutorial or a search on the Internet, you will know, here is a recommended Android capture package -Charles[2], for your reference

Over Https protocol

Once configured, you might notice that Charles has captured packages that are garbled because the applet must use the Https protocol

This is to encrypt the request data on top of the Http assistance to prevent man-in-the-middle attacks

The principle of Https is also very simple. The target URL applies for an Https certificate, and then publishes the public key of its symmetric key on the website that issues the certificate

When the target server is visited by the request, the target server will ask it to make a refill request, which is the client program will automatically go to the certificate issuing site to download the target website’s public key, that is, the certificate

The requested data is encrypted with the public key and sent to the target server. After receiving the request, the target server decrypts the requested data with its private key and converts it into plaintext for further processing

The same is true when the response is returned, except that the target server encrypts it with its private key and the client decrypts it with its public key

For details, please refer to the diagram HTTP[3]

Here you just need to follow Charles’ instructions, and then follow the certificate issued by Charles on the mobile phone

However, if you are running Android, please note that Google has updated its security policy since Android 7.0 to no longer support self-installed certificates

There are two solutions:

  1. Root the mobile phone, and then modify the security policy of the mobile phone. For details, please refer to: Capture Android Https link data through Charles [4]
  2. Find a phone that has not been upgraded to Android 7.0

I dug out a phone from a few years ago, charged it, turned it on, and checked the version. It was Android 6

After installing the certificate and capturing the packet again, you can see the requested data \

Charles caught

Get familiar

Once you have the request link and the request data, you can write Python scripts as you did last time

Last time, the request data was retrieved via a browser request. In Charles, it is also easy to retrieve, as shown below

Charles fetch request

Obtain the curl request data from the shortcut menu and copy it to curl.trillworks.com/[5]

Charles fetch request

Then copy the Python code to a file and execute it. Easy enough, see the previous article: This is the correct way to use Python! [6]

further

There’s another problem that needs to be solved here. Maybe I’m too lazy as a dad

Because of the May Day holiday, the Saturday after the holiday is a working day, and the previous procedure will book the course of every Saturday. If it is a working day, it just conflicts

So need to avoid working days, so the first thing to think of is to judge the holiday library available, find a circle, found some API can, but not need to pay is the need to register, more trouble, so directly go to the calendar to grab

Lock a universal calendar website wannianrili.bmcx.com, marked clear, accurate data, and free

calendar

Analysis request, it is a month of data accessed by the link wannianrili.bmcx.com/ajax/, access to the results of the data is in XML format

According to the analysis, date types are marked by CSS classes, namely wnrl_RIQI_BAN, wnrL_RIqi_MO, and wnrl_RIqi_XIU, representing work, weekend, and rest

So you just need to parse the XML you get

Further – because here I am again for a month, each request access point charge again, and it is in the booking, so I need a higher efficiency (ha ha, is actually want to dazzle technique), then made a small cache, every time see if there are any XML files for the month, if you have read directly, without access to, and stored

After the realization of the holiday judgment, add a judgment in the main booking program, if the day to make an appointment is a working day, then postpone one day, continue to judge, until a fee working day

Here is the code to determine the date type:

import requests
from lxml import etree
import datetime
import os

def getDaysInfo(ym):
    cacheName = ym + ".html"
    if os.path.exists(cacheName):
        content = open(cacheName).read()
    else:
        content = requestsDayInfo(ym)
        saveFile(cacheName, content)
    
    return content

def requestsDayInfo(ym=None):
    headers = {
        'sec-ch-ua''"Google Chrome"; v="89", "Chromium"; v="89", "; Not A Brand"; v="99"'.'Referer''https://wannianrili.bmcx.com/'.'sec-ch-ua-mobile''? 0 '.'User-Agent''the Mozilla / 5.0 (Windows NT 10.0; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
    }
    params = (
        ('q', ym),
        ('v'.'20031912'),
    )
    response = requests.get('https://wannianrili.bmcx.com/ajax/', headers=headers, params=params)
    return response.text

def saveFile(name, content):
    print(name)
    f = open(name,'w')
    f.write(content)
    f.close()

def parse(content, d):
    html = etree.HTML(content)
    dayclass = html.xpath('//*[@id="wnrl_riqi_id_'+str(int(d)- 1) +'"]) [0].attrib.get('class')

    if dayclass is None or dayclass == 'wnrl_riqi_ban':
        return 1
    elif dayclass == 'wnrl_riqi_mo':
        return 2
    elif dayclass == 'wnrl_riqi_xiu':
        return 3
    else:
        return 0

def getDayType(date):
    str_date = date.strftime('%Y-%m-%d')
    ymd = str_date.split("-")
    ym = ymd[0] + The '-' + ymd[1]
    d = ymd[2]
    return parse(getDaysInfo(ym), d)

if __name__ == "__main__":
    delta = 1Date = datetime.date.today() while(getDayType(date)< datetime.date.today())2):
        delta += 1
        date = datetime.date.today() + datetime.timedelta(days=delta)
Copy the code

conclusion

Ok, now you can be an elegant dad again. Haha, the best way to teach your kids is to grow up with them. Whatever it is, if you happen to like programming and know how to program, you can try doing something fun with your kids, like making a dice game. [7]

ink

The resources

[1]

Python lesson about: mp.weixin.qq.com/s/XqICwC9_c…

[2]

Android caught: www.jianshu.com/p/8385a13b0…

[3]

The illustration HTTP: book.douban.com/subject/258…

[4]

Android 7.0 installation certificate: bbs.huaweicloud.com/blogs/24501…

[5]

Curl to Python request: curl.trillworks.com/

[6]

This is the correct posture for using Python! : mp.weixin.qq.com/s/XqICwC9_c…

[7]

A dice game: mp.weixin.qq.com/s/czcGKk6RT…

PS: Reply “Python” within the public number to enter the Python novice learning exchange group, together with the 100-day plan!

Old rules, brothers still remember, the lower right corner of the “watching” click, if you feel the content of the article is good, remember to share moments to let more people know!

[Code access ****]

Identify the qr code at the end of the article, reply: 0506