日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

上次寫(xiě)的如何給小孩約馬術(shù)課過(guò)程,見(jiàn)這里 Python 約課[1], 本想一勞永逸,但是好景不長(zhǎng),預(yù)約系統(tǒng)升級(jí)了,而且還換了服務(wù)商,從之前的公眾號(hào) H5 應(yīng)用,換成了小程序,之前編寫(xiě)的方式直接失效,孩子又沒(méi)馬騎了

誰(shuí)叫他遇到一個(gè)程序員老爸呢?這點(diǎn)事兒難不倒我,開(kāi)干

小程序的不同之處

與訪問(wèn) H5 不同的是,小程序相當(dāng)于一個(gè) App,其上的操作是經(jīng)過(guò)微信的封裝的,所以無(wú)法直接獲取到請(qǐng)求鏈接和數(shù)據(jù),同樣也無(wú)法獲得返回的數(shù)據(jù)

就像一個(gè) app,他的請(qǐng)求都是內(nèi)置在程序內(nèi)的

對(duì)于這種情況,就需要使用抓包工具,比如 Charles

它的原理是,作為請(qǐng)求的代理,即小程序 或 app 發(fā)送請(qǐng)求時(shí),先將請(qǐng)求發(fā)送給代理,然后再由代理將請(qǐng)求發(fā)送給服務(wù)器,返回的過(guò)程也一樣

這也是著名的 中間人攻擊

不能爬小程序,叫什么會(huì)爬蟲(chóng)

中間人攻擊

如果要獲取 小程序或者 app 的具體請(qǐng)求,就需要用這種方式,讓代理獲取請(qǐng)求和相應(yīng)的數(shù)據(jù)

具體這么玩呢?直接參考 Charles 教程或者在網(wǎng)上一搜,就知道了,這里推薦一篇Android抓包-Charles[2],供各位參考

飛越 Https 協(xié)議

如果配置好了之后,可能發(fā)現(xiàn) Charles 抓的包全是亂碼,這是因?yàn)?小程序必須使用 Https 協(xié)議

也就是在 Http 協(xié)助之上對(duì)請(qǐng)求數(shù)據(jù)做一次加密,以防止中間人攻擊

Https 的原理也很簡(jiǎn)單,就是目標(biāo)網(wǎng)址申請(qǐng)一個(gè) https 證書(shū),然后將其對(duì)稱(chēng)密鑰的公鑰發(fā)布在頒發(fā)證書(shū)的網(wǎng)站上

當(dāng)由請(qǐng)求訪問(wèn)目標(biāo)服務(wù)器時(shí),目標(biāo)服務(wù)器會(huì)要求其進(jìn)行加滿請(qǐng)求,這是客戶(hù)端程序會(huì)自動(dòng)去證書(shū)頒發(fā)網(wǎng)址下載目標(biāo)網(wǎng)站的公鑰,也就是證書(shū)

然后對(duì)請(qǐng)求的數(shù)據(jù)用公鑰加密,再發(fā)送到目標(biāo)服務(wù)器上,目標(biāo)服務(wù)器收到請(qǐng)求后,會(huì)用自己的私鑰解密請(qǐng)求數(shù)據(jù),轉(zhuǎn)化為明文繼續(xù)處理

當(dāng)返回響應(yīng)時(shí)也是一樣的,不過(guò)目標(biāo)服務(wù)器用自己的私鑰加密,客戶(hù)端用公鑰解密

詳細(xì)說(shuō)明可參考 圖解HTTP[3]

這里只需要按照 Charles 的說(shuō)明,在手機(jī)端按照 Charles 頒發(fā)的證書(shū)就可以了

不過(guò)如果用的是 Android 系統(tǒng)的話,需要注意 Android 7.0 之后 谷歌升級(jí)了安全策略,不再支持用戶(hù)自主安裝的證書(shū)

有兩個(gè)解決辦法:

  1. 對(duì)手機(jī)做root,然后修改手機(jī)的安全策略,詳細(xì)可參考: 通過(guò)Charles抓取Android的Https鏈接數(shù)據(jù)[4]
  2. 找一個(gè)未升級(jí)到 Android 7.0 的手機(jī)

翻出了一臺(tái)幾年前的手機(jī),充電,開(kāi)機(jī),查看版本,是 Android 6,哈哈,太幸運(yùn)了

不能爬小程序,叫什么會(huì)爬蟲(chóng)

 

安裝好證書(shū)后,再次抓包,就可以看見(jiàn)請(qǐng)求的數(shù)據(jù)了

不能爬小程序,叫什么會(huì)爬蟲(chóng)

Charles 抓包

輕車(chē)熟路

得到了請(qǐng)求鏈接和請(qǐng)求數(shù)據(jù),就可以像上一次一樣編寫(xiě)成 Python 腳本了

上一次是通過(guò)瀏覽器中請(qǐng)求的方式獲取的請(qǐng)求數(shù)據(jù),在 Charles 中,獲取也很方便,如下圖

不能爬小程序,叫什么會(huì)爬蟲(chóng)

Charles 獲取請(qǐng)求

通過(guò)快捷菜單,獲取 curl 命令的請(qǐng)求數(shù)據(jù),然后復(fù)制到 網(wǎng)站

不能爬小程序,叫什么會(huì)爬蟲(chóng)

Charles 獲取請(qǐng)求

然后將 python 代碼拷出到文件里,執(zhí)行即可,夠簡(jiǎn)單吧,具體可以參考之前的文章: 這才是使用Python的正確姿勢(shì)![6] 的文章描述

更進(jìn)一步

這里還需要解決一個(gè)問(wèn)題,可能是我這個(gè)做老爸的實(shí)在太懶了

因?yàn)檎滴逡患倨?,假期結(jié)束后的一個(gè)周六是工作日,而之前的程序會(huì)預(yù)約每周六的課程,如果是工作日的話,剛好沖突了

所以需要避開(kāi)工作日,那么首先想到的是有沒(méi)有判斷節(jié)假日的庫(kù)可用,找了一圈,發(fā)現(xiàn)有些 api 可以,但是不是需要付費(fèi)就是需要注冊(cè),比較麻煩,于是直接去萬(wàn)年歷中去抓取

鎖定的一個(gè)萬(wàn)能歷史網(wǎng)站,標(biāo)記清晰,數(shù)據(jù)準(zhǔn)確,而且免費(fèi)

不能爬小程序,叫什么會(huì)爬蟲(chóng)

萬(wàn)年歷

分析請(qǐng)求,是通過(guò)鏈接獲取一個(gè)月的數(shù)據(jù),獲取的結(jié)果是 xml 格式的數(shù)據(jù)

分析發(fā)現(xiàn),日期類(lèi)型是通過(guò) css 的類(lèi)來(lái)標(biāo)記的,分別是 wnrl_riqi_ban,wnrl_riqi_mo,wnrl_riqi_xiu,表示 上班,周末 和 休息

所以只需要對(duì)獲取的 xml 進(jìn)行解析就好了

這里我又再進(jìn)一步 —— 因?yàn)楂@取的是一個(gè)月的,每次請(qǐng)求獲取又點(diǎn)費(fèi),而且是在搶預(yù)約,所以需要更高的效率(哈哈,實(shí)際上是想炫炫技而已),于是做了一個(gè)小緩存,每次看看有沒(méi)有當(dāng)月的 xml 文件,如果有直接讀取,沒(méi)有則獲取,并存儲(chǔ)起來(lái)

實(shí)現(xiàn)了節(jié)假日判斷后,在主預(yù)約程序里加一個(gè)判斷,如果要預(yù)約的日子是工作日,再后延一日,繼續(xù)判斷,直到遇到一個(gè)非工作日

這里展示一下判斷日期類(lèi)型的代碼:

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': '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] + '-' + ymd[1]
    d = ymd[2]
    return parse(getDaysInfo(ym), d)

if __name__ == "__main__":
    delta = 1  # 探索步長(zhǎng)為一日
    date = datetime.date.today()
    while(getDayType(date)<2):
        delta += 1
        date = datetime.date.today() + datetime.timedelta(days=delta)

總結(jié)

好了,現(xiàn)在又可以做優(yōu)雅的老爸了哈哈,對(duì)孩子最好的教育就是陪孩子一起成長(zhǎng),無(wú)論是什么方面,如果你恰巧喜歡編程,會(huì)編程的話,可以嘗試和孩子一起做些有意思的東西,比如 做個(gè)擲骰子游戲[7]

分享到:
標(biāo)簽:爬蟲(chóng)
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定