<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          送書 | 用啥selenium!JS逆向不香嗎?

          共 12779字,需瀏覽 26分鐘

           ·

          2021-09-10 13:15


          大家好!我是啃書君

          正所謂條條道路通羅馬,上次我們使用了Selenium自動化工具來爬取網(wǎng)易云的音樂評論,Selenium自動化工具可以驅(qū)動瀏覽器執(zhí)行特定的動作,獲得瀏覽器當(dāng)前呈現(xiàn)的頁面的源代碼,做到可見即可爬,但需要等網(wǎng)頁完全加載完,也就是JavaScript完全渲染出來才可以獲取到當(dāng)前的網(wǎng)頁源代碼,這樣的爬取效率太低了、爬取速度太慢了。

          追求完美、追求高效率的我們,怎么會容忍效率低下呢?所以我們今天利用Scrapy框架加js逆向來爬取網(wǎng)易云評論并做詞云圖,做效率最高的人?。?!

          在爬取前,我們首先要了解一下什么是js逆向。

          js逆向

          首先Javascript簡稱js,js是一種腳本語言,是不需要進(jìn)行編譯的,也是瀏覽器中的一部分,經(jīng)常用在web客戶端腳本語言,主要是用來給html增加動態(tài)功能,也可以進(jìn)行數(shù)據(jù)加密。

          加密在前端開發(fā)和爬蟲中是很常見的,當(dāng)我們掌握了加密算法且可以將加密的密文進(jìn)行解密破解時,就可以從編程小白搖身變?yōu)榫幊檀笊?,熟練掌握加密算法可以幫助我們實現(xiàn)高效的js逆向。由于加密算法的內(nèi)容有很多,今天我們主要是簡單了解一下加密算法有哪些,之前有寫過加密算法,感興趣可以看看往期文章?。。?/p>

          常見的加密算法

          js中常見的加密算法有以下幾種:

          • 線性散列MD5算法:保證文件的正確性,防止一些人盜用程序,加些木馬或者篡改版權(quán),設(shè)計的一套驗證系統(tǒng),廣泛用于加密和解密技術(shù)上,如用戶的密碼;
          • 對稱加密DES算法:是一種使用密鑰加密的算法,其加密運(yùn)算、解密運(yùn)算需要使用的是同樣的密鑰,加密后密文長度是8的整數(shù)倍;
          • 對稱加密AES算法:是DES算法的加強(qiáng)版,采用分組密碼體制,加密后密文長度是16的整數(shù)倍,匯聚了強(qiáng)安全性、高性能、高效率、易用和靈活等優(yōu)點,比DES算法的加密強(qiáng)度更高,更安全;
          • 非對稱加密算法RSA:在公開密鑰加密和電子商業(yè)中被廣泛使用,需要公開密鑰和私有密鑰,只有對應(yīng)的私有密鑰才能解密;
          • base64偽加密:是一種用64個字符表示任意二進(jìn)制數(shù)據(jù)的方法,只是一種編碼方式而不是加密算法;
          • https證書秘鑰加密:基于http和SSL/TLS實現(xiàn)的一個協(xié)議,保證在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)都是加密的,從而保證數(shù)據(jù)安全。

          js逆向作用

          我們發(fā)送網(wǎng)絡(luò)請求的時候,往往需要攜帶請求參數(shù),如下圖所示:

          有爬蟲基礎(chǔ)的人都知道,上圖發(fā)送的是POST網(wǎng)絡(luò)請求,在發(fā)送請求時,我們還要攜帶一些參數(shù),例如上圖中的limit和current,其中l(wèi)imit是每次獲取的數(shù)據(jù)個數(shù),current是頁碼數(shù)。要想獲取上面的URL鏈接所呈現(xiàn)中的數(shù)據(jù)時,必須要在發(fā)送網(wǎng)絡(luò)請求時攜帶limit和current這兩個參數(shù)。

          有時候我們需要攜帶的請求參數(shù)是加密過的參數(shù),如下圖所示:

          同樣是發(fā)送POST網(wǎng)絡(luò)請求,很明顯這次的參數(shù)是已經(jīng)加密過的參數(shù),該參數(shù)是一大串不知道表達(dá)什么意思的字符串,這時就需要采用js逆向來破解該參數(shù)。有人可能說,直接復(fù)制粘貼那參數(shù),也獲取到數(shù)據(jù)呀。可是這樣只能獲取到一小部分?jǐn)?shù)據(jù)或者一頁的數(shù)據(jù),不能獲取到多頁。

          通過上面的例子,我們可以知道,js逆向可以幫助我們破解加密過的參數(shù)。

          當(dāng)然除了幫我們破解加密過的參數(shù),還可以幫我們處理以下事情:

          • 模擬登錄中密碼加密和其他請求參數(shù)加密處理;
          • 動態(tài)加載且加密數(shù)據(jù)的捕獲和破解;

          js逆向的實現(xiàn)

          那么如何實現(xiàn)js逆向或者破解加密過的參數(shù)呢。

          要破解加密過的參數(shù),大致可以分為四步:

          1. 尋找加密參數(shù)的方法位置找出來;
          2. 設(shè)置斷點找到未加密參數(shù)與方法;
          3. 把加密方法寫入js文件;
          4. 調(diào)試js文件。

          下面我們以待會要爬取的網(wǎng)易云音樂評論為例,所創(chuàng)建的js文件名為wangyi.js,來演示一下如何實現(xiàn)js逆向。

          尋找加密函數(shù)位置

          首先打開開發(fā)者模式,找到你要獲取的數(shù)據(jù)的URL請求條目,再把加密參數(shù)的變量復(fù)制下來,點擊右上角三個小點,選擇Search。

          在通過Search搜索把加密參數(shù)函數(shù)的存放位置找出來,如下圖所示:

          經(jīng)過選擇我們發(fā)現(xiàn)加密函數(shù)放在core_b15...中,點擊4126這一行就會打開core_b15...,我們再在core_b15...中搜索有沒有其他params,鍵盤同時按下Ctrl F,如下圖所示:

          由上圖可知,core_b15...中有34個params,這34個params中都有可能是加密參數(shù),這里我們來告訴大家一個小技巧,一般情況下,加密參數(shù)都是以下形式輸出的,

          參數(shù):
          參數(shù) =

          所以我們可以在搜索框中稍稍加點東西,例如把搜索框中的params改為params:,結(jié)果如下圖所示:

          這樣params就被我們精確到只有兩個,接下來我們開始設(shè)置斷點。

          設(shè)置斷點找到未加密參數(shù)與函數(shù)

          在上一步中,我們把params的范圍縮短到只有兩處,如下圖所示:

          第一種圖的params只是一個類似字典的變量,而第二張圖的params:bYm0x.encText,表示在bYm0x中選取encText的值賦給params,而在13367行代碼中,表示encSecKey為bYm0x中encSecKey的值,所以我們可以通過變量bYm0x來獲取,而在params:bYm0x.encText上兩行代碼中,bYm0x變量中window調(diào)用了asrsea()方法,13364行代碼是我們加密參數(shù)的函數(shù)。我們把鼠標(biāo)放在window.asrsea中間,如下圖所示:

          由上圖可知,window.asrsea通過function d函數(shù)中調(diào)用的,其傳入?yún)?shù)為d,e,f,g,點擊f d(d,e,f,g),如下圖所示:

          當(dāng)我們不知道從哪里設(shè)置斷點時,我們可以嘗試在它調(diào)用函數(shù)的一行設(shè)置斷點或者你認(rèn)為哪行代碼可疑就在哪行代碼設(shè)置斷點,刷新頁面,如下圖所示:

          點擊上圖的1,一步步放開斷點,注意觀察上圖中的2,3處的變化,如下圖如下圖所示:

          當(dāng)左邊出現(xiàn)了評論區(qū),但沒出現(xiàn)評論內(nèi)容時,這時右邊的方框剛好出現(xiàn)了d,e,f,g這三個數(shù)據(jù),而且d中的數(shù)字剛好是歌曲的id。我們這四個參數(shù)復(fù)制下來,并去除\,觀察一下:

          d: "{"rid":"R_SO_4_1874158536","threadId":"R_SO_4_1874158536","pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}"
          e: "010001"
          f: "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
          g: "0CoJUm6Qyw8W8jud"

          通過上面的代碼,我們推測rid和threadId是單曲id,pageNo是評論區(qū)的頁數(shù),pageSize是評論數(shù)據(jù)的行數(shù),其他的不認(rèn)識?。?!

          為了證實推測,我們換個歌單來測試獲取d,e,f,g這四個參數(shù):

          d: "{"rid":"A_PL_0_6892176976","threadId":"A_PL_0_6892176976",\"pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}"
          e: "
          010001"
          f: "
          00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
          g: "
          0CoJUm6Qyw8W8jud"

          通過觀察可以發(fā)現(xiàn),我們的推測是正確的,而且e,f,g是固定不變的,那么我們可以確定參數(shù)d中的參數(shù)就是未加密的參數(shù),既然找到了未加密的參數(shù),那么我們先把未加密的參數(shù)寫入js文件中。

          注意:rid中的A_PL_0代表的是歌單,而R_SO_4代表的是單曲。

          把加密參數(shù)的方法寫入js文件

          未加密的參數(shù)我們在上一步已經(jīng)獲取到了,也就知道了加密參數(shù)的函數(shù)為接下來開始把加密參數(shù)的方法并寫入js文件中。

          該加密參數(shù)方法如下圖所示:

          加密參數(shù)方法為window.asrsea(),所以我們直接復(fù)制粘貼第13364行代碼作為我們的加密參數(shù)方法,并寫在入口函數(shù)中,并返回變量bYm0x,具體代碼如下所示:

          function start(){
              var bYm0x = window.asrsea(JSON.stringify(i8a), bqf4j(["流淚""強(qiáng)"]), bqf4j(Sr6l.md), bqf4j(["愛心""女孩""驚恐""大笑"]));
              return bYm0x
          }

          將鼠標(biāo)放在window.asrsea中間,如下圖所示:

          在圖中我們可以知道window.asrsea()調(diào)用了function d函數(shù),而傳入的參數(shù)對應(yīng)著未加密的參數(shù)d、e、f、g,而d屬于字典,e、f、g屬于常量,所以我們可以把上面的代碼改寫為:

          function start(){
              var bYm0x=window.asrsea(JSON.stringify(d),e,f,g);
              return bYm0x
          }

          寫了入口函數(shù)后,我們開始觀察function d函數(shù),如下圖所示:

          通過function d()函數(shù),我們發(fā)現(xiàn)function d()函數(shù)調(diào)用了a()函數(shù)、b()函數(shù)、c()函數(shù),所以我們要把這些函數(shù)都復(fù)制在剛才的js文件中。當(dāng)我們不知道要復(fù)制哪些代碼時,就直接復(fù)制function d函數(shù)的外面一層花括號的所有代碼,也就是第13217行代碼為復(fù)制的開始點,第13257行代碼為復(fù)制的結(jié)束點。

          為了我們的js文件可以在控制臺看到調(diào)試的結(jié)果,我們需要添加以下代碼:

          console.log(start())

          調(diào)試js文件

          好了,我們已經(jīng)把代碼復(fù)制在js文件中了,在調(diào)試js文件前,我們先安裝node.js和node.js插件。

          node.js

          node.js安裝方式很簡單,進(jìn)入node.js官網(wǎng),如下圖所示:

          大家選擇對應(yīng)的系統(tǒng)來下載安裝,由于安裝實在太簡單了,都是無腦下一步就可以了,當(dāng)然最好參照網(wǎng)上的教程來安裝,這里我們就不講解如何安裝node.js。

          注意:一定要安裝node.js,否則會在調(diào)試js文件中報以下錯誤:

          execjs._exceptions.ProgramError: TypeError: ‘JSON‘ 未定義

          node.js插件

          我們寫好js文件后,需要進(jìn)行調(diào)試,而在pycharm中調(diào)試js文件需要安裝node.js插件。

          首先進(jìn)入pycharm中的setting配置,如下圖所示:

          按照上圖中的步驟,即可安裝好插件。

          好了,準(zhǔn)備工作已經(jīng)做好了,現(xiàn)在開始調(diào)試js文件,運(yùn)行剛才的js文件,會發(fā)現(xiàn)報了以下錯誤:

          window.asrsea = d,
          ^

          ReferenceError: window is not defined

          該錯誤是說window沒定義,這時我們只需要在最前面添加以下代碼即可:

          window={}

          進(jìn)行運(yùn)行我們的js文件,發(fā)現(xiàn)又報錯了,錯誤如下所示:

                  var c = CryptoJS.enc.Utf8.parse(b)
                          ^

          ReferenceError: CryptoJS is not defined

          錯誤提示又是參數(shù)沒定義,但CryptoJS就不能簡單的設(shè)置一個空字典,這需要我們繼續(xù)在剛才的core_b15...中尋找CryptoJS了,如下圖所示:

          由圖中可知,CryptoJS一共要13處那么多,那么我們該從何開始復(fù)制呢,又從何處結(jié)束復(fù)制呢,當(dāng)我們不知道在哪里開始復(fù)制時,直接把所有的CrpytoJS都復(fù)制下來,請記住一個原則,寧愿復(fù)制多了也不復(fù)制少了,多了不會報錯,少了會報錯,而且還要找錯,重新復(fù)制。

          好了,我們復(fù)制完后,繼續(xù)運(yùn)行js文件。

          運(yùn)行結(jié)果如下:

          好了,js文件已經(jīng)運(yùn)行準(zhǔn)確無誤了。接下來開始爬取數(shù)據(jù)

          數(shù)據(jù)爬取

          我們是通過Scrapy框架來爬取數(shù)據(jù),所以我們首先來創(chuàng)建Scrapy項目和spider爬蟲。

          創(chuàng)建Scrapy項目、Spider爬蟲

          創(chuàng)建Scrapy項目和Spider爬蟲很簡單,依次執(zhí)行以下代碼即可:

          scrapy startproject <Scrapy項目名>
          cd <Scrapy項目名>
          scrapy genspider <爬蟲名字> <允許爬取的域名>

          其中,我們的Scrapy項目名為NeteaseCould,爬蟲名字為:NC,允許爬取的域名為:music.163.com。

          好了創(chuàng)建Scrapy項目后,接下來我們創(chuàng)建一個名為JS的文件夾來存放剛才編寫的js文件,項目目錄如下所示:

          這里我們還創(chuàng)建了一個名為Read_js.py文件,該文件用來讀取js文件。

          讀取js文件——Read_js.py

          我們編寫好js文件后,當(dāng)然要把它讀取出來,具體代碼如下所示:

          def get_js():
              path = dirname(realpath(__file__)) + '/js/' + 'wangyi' + '.js'
              with open(path,'r',encoding='utf-8')as f:
                  r_js=f.read()
              c_js=execjs.compile(r_js)
              u_js=c_js.call('start')
              data={
                  "params":u_js['encText'],
                  "encSecKey":u_js['encSecKey']
              }
              return data

          我們把讀取到的js文件內(nèi)容存放在r_js變量中,然后通過execjs.compile()方法獲取代碼編譯完成后的對象,再通過call()方法來調(diào)用js文件中的入口函數(shù),也就是start()函數(shù)。然后將獲取到的數(shù)據(jù)存放在字典data中,最后返回字典data。

          對了,為了使我們的代碼更靈活,我們可以把參數(shù)d放在Read_js.py文件中,具體代碼如下所示:

              url = 'https://music.163.com/#/song?id=17177324'
              id = url.split('=')[-1]
              d = {
                  "rid"f"R_SO_4_{id}",
                  "threadId"f"R_SO_4_{id}",
                  "pageNo""1",
                  "pageSize""5",
                  "cursor""-1",
                  "offset""0",
                  "orderType""1",
                  "csrf_token"""
              }
              u_js=c_js.call('start',d)

          首先利用split()方法把歌曲的id獲取下來,然后放在參數(shù)d中,當(dāng)我們需要獲取另一首歌的評論信息的時候,只需要修改上面的url即可。注意:參數(shù)d中R_SO_4代表的單曲,當(dāng)我們要獲取其他的評論信息時,則需要更改R_SO_4,例如獲取歌單的時候則需要更改為A_PL_0。

          items.py文件

          在獲取數(shù)據(jù)前,我們先在items.py文件中,定義爬取數(shù)據(jù)的字典,具體代碼如下所示:

          import scrapy

          class NeteasecouldItem(scrapy.Item):
              # define the fields for your item here like:
              name = scrapy.Field()
              content = scrapy.Field()

          NC.py文件

          在定義字段后,先看看評論數(shù)據(jù)的位置,如下圖所示:

          現(xiàn)在我們開始獲取網(wǎng)易云音樂評論的數(shù)據(jù),具體代碼如下所示:

          import scrapy
          from NeteaseCould.Read_js import get_js
          from NeteaseCould.items import NeteasecouldItem
          class NcSpider(scrapy.Spider):
              name = 'NC'
              allowed_domains = ['music.163.com']
              start_urls = ['https://music.163.com/weapi/comment/resource/comments/get?csrf_token=']

              def start_requests(self):
                  js=get_js()
                  yield scrapy.FormRequest('https://music.163.com/weapi/comment/resource/comments/get?csrf_token=',formdata=js,callback=self.parse)

              def parse(self, response):
                  json=response.json()
                  p=json.get('data').get('comments')
                  for i in p:
                      item = NeteasecouldItem()
                      item['content']=i.get('content')
                      yield item

          首先我們導(dǎo)入get_js和NeteasecouldItem,再將start_urls中的鏈接修改為https://music.163.com/weapi/comment/resource/comments/get?csrf_token=。

          由于我們發(fā)送的是POST請求,所以我們需要重寫start_requests()方法,在start_requests()方法中,我們先調(diào)用了get_js()方法,然后在通過ForMReuqest()方法發(fā)送網(wǎng)絡(luò)請求。

          其中,formdata=相當(dāng)于我們普通爬蟲的data=callback=self.parse()表示將響應(yīng)返回給parse()方法。

          最后通過parse()方法進(jìn)行數(shù)據(jù)的獲取并通過yield生成器返回給引擎。

          pipelines.py文件

          當(dāng)我們需要把數(shù)據(jù)放在數(shù)據(jù)庫或者存放在.txt文件中數(shù),則需要在pipelines.py文件編寫代碼,這里我們把數(shù)據(jù)存放在txt文件中,具體代碼如下所示:

          from itemadapter import ItemAdapter

          class NeteasecouldPipeline:
              def process_item(self, item, spider):
                  with open('評論.txt','a',encoding='utf-8')as f:
                      f.write(item['content'])
                      f.write('\n')

          獲取多條評論

          對了,如何獲取多條評論呢,通常情況下,我們需要進(jìn)行翻頁來獲取多條評論,但是這次不同,我們可以修改參數(shù)d中的數(shù)據(jù)就可以獲取多條評論,參數(shù)d如下所示:

          d = {
              "rid": f"R_SO_4_{id}",
              "threadId": f"R_SO_4_{id}",
              "pageNo""1",
              "pageSize""5",
              "cursor""-1",
              "offset""0",
              "orderType""1",
              "csrf_token"""
          }

          我們可以修改pageSize的數(shù)據(jù),例如我現(xiàn)在的pageSize對應(yīng)的是5,所以只獲取五條評論。

          settings.py文件

          最后,我們需要在settings.py文件中做一些配置,具體代碼如下:

          #屏蔽日志的輸出
          LOG_LEVEL="WARNING"

          #開啟引擎
          ITEM_PIPELINES = {
             'NeteaseCould.pipelines.NeteasecouldPipeline': 300,
          }

          結(jié)果展示

          所有的代碼已經(jīng)編寫完畢了,現(xiàn)在我們開始運(yùn)行爬蟲,執(zhí)行如下代碼:

          scrapy crawl NC

          運(yùn)行結(jié)果如下:

          制作詞云

          制作詞云我們需要jieba庫,wordcloud庫、imageio庫,其安裝方式如下:

          pip install jieba
          pip install wordcloud
          pip install imageio

          在前面的步驟中,我們已經(jīng)成功獲取到評論并把評論數(shù)據(jù)保存在txt文本中,接下來我們將開始制作詞云,具體代碼如下:

          import jieba
          import wordcloud
          import imageio
          img_read=imageio.imread('小熊.jpg')
          file_open=open('評論.txt''r', encoding='utf-8')
          txt=file_open.read()
          Cloud=wordcloud.WordCloud(width=1000,height=1000,background_color='white',mask=img_read,scale=8,font_path='C:\Windows\Fonts\msyhbd.ttc',stopwords={'的','了','是'})
          txtlist=jieba.lcut(txt)
          string=' '.join(txtlist)
          Cloud.generate(string)
          Cloud.to_file('小熊.png')

          首先我們導(dǎo)入jieba、wordcloud、imageio庫,再調(diào)用imageio.imread()方法來讀取詞云的背景圖,然后再調(diào)用wordcloud.WordCloud()方法,把詞云圖設(shè)置寬高為1000,背景色為白色,詞云圖背景為剛才讀取的圖片。

          注意:當(dāng)我們做的詞云有中文時,我們要把系統(tǒng)文字路徑傳入到wordcloud.WordCloud()方法中,這里我們還把“的,了,是”在詞云中屏蔽掉。

          然后我們調(diào)用jieba.lcut()方法把text.txt文本中的文字進(jìn)行切割,由于我們分割出來的文字是以列表的形式保存的,所以調(diào)用join()方法把列表轉(zhuǎn)換為字符

          最后調(diào)用generate()方法生成詞云,調(diào)用to_file()方法保存詞云圖。

          結(jié)果展示

          好了,js逆向爬取網(wǎng)易云音樂評論并做詞云就講到這里了,感謝觀看!?。?/p>

          啃書君說

          本文僅用于學(xué)術(shù)交流!文章的每一個字都是我用心寫出來的,如果你看到了這里,希望可以得到你的【點贊】與【在看】,讓我知道你就是那個陪我一起努力的人。

          我是啃書君,一個專注于學(xué)習(xí)的人,更多精彩內(nèi)容,我們下期再見!

          送書

          又到了每周三的送書時刻,今天給大家?guī)淼氖恰?span style="outline: 0px;font-family: Arial, "microsoft yahei";font-size: 16px;font-weight: 700;letter-spacing: 0.544px;">反爬蟲AST原理與還原混淆實戰(zhàn)》,AST是目前爬蟲領(lǐng)域的熱點。本書從AST這一個知識點出發(fā),由淺入深,帶領(lǐng)讀者掌握反爬蟲AST的原理,并幫助讀者培養(yǎng)解決實際問題的能力。本書共11章,分為四部分。第一部分(第1~4章)介紹開發(fā)環(huán)境的搭建方法、Web調(diào)試的必備技巧以及爬蟲與反爬蟲的基本知識;第二部分(第5~6章)講解混淆JavaScript代碼的手工逆向方法與JavaScript代碼安全防護(hù)的原理;第三部分(第7~8章)講解AST的原理與API的使用方法;第四部分(第9~11章)以AST為基礎(chǔ),講解自動化的JavaScript代碼防護(hù)與還原方案,并帶領(lǐng)讀者進(jìn)行實戰(zhàn)訓(xùn)練。本書適合作為計算機(jī)培訓(xùn)的教材,也可供安全開發(fā)人員、爬蟲初學(xué)者以及想要在爬蟲領(lǐng)域進(jìn)階的人員學(xué)習(xí)。




          公眾號回復(fù):送書 ,參與抽獎(共3本)

          點擊下方回復(fù):送書  即可!


          ???????????????????????


          大家如果有什么建議,歡迎掃一掃二維碼私聊小編~
          回復(fù):加群 可加入Python技術(shù)交流群


             (點擊查看本書內(nèi)容)

          瀏覽 94
          1點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          1點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉狠狠撸手机免费看视频 | 日皮视频免费网站 | 男女h网站 | 黑人大鸡吧操美女大逼 | 国产视频精品i |