熱線電話:13121318867

登錄
首頁精彩閱讀Python高效實現滑塊驗證碼自動操縱
Python高效實現滑塊驗證碼自動操縱
2022-02-17
收藏
Python高效實現滑塊驗證碼自動操縱

CDA數據分析師

出品作者:CDALevel Ⅰ

持證人崗位:數據分析師

行業:大數據

眾所周知,規范性的網絡爬蟲可以幫助Decision-maker在低成本下獲得想要的信息,不僅如此,做科研、寫論文、包括現在的大學生都可以利用該技術獲得相應的數據。在數據為王的時代,網絡爬蟲是每個coder都需要必備的技能。然而,隨著爬蟲事業的發展,網站也開始部署了一些反爬蟲措施,最典型的莫過于12306等網站。其中,驗證碼是常用的表單登錄反爬蟲措施。coder在編寫程序爬蟲的時候或多或少都會遇到驗證碼的人機判別。當然,驗證碼不是一成不變的,隨著互聯網技術的發展,驗證碼的樣式也變得越來越多。比如包括中文漢字、中文符號、英文字符的圖形驗證碼、移動滑塊驗證碼、滑動宮格驗證碼、計算題驗證碼、點觸驗證碼等等。

本文選擇目前市場上較為流行且難度較大的移動滑塊驗證碼,并在介紹其樣式的基礎上進一步選擇更為高級的無原圖有空隙的移動滑塊驗證碼,利用Python語言結合超級鷹平臺高效實現滑塊路徑長度的計算,并以小不點搜索網址(https://www.xiaoso.net/)作為案例作為代碼實現,使讀者更為直觀的體驗。

本文采用Anaconda進行Python編譯,主要涉及的Python模塊:

  • PIL
  • chaojiying
  • time
  • selenium

本章分為三部分講解:

  1. 移動滑塊驗證碼樣式背景
  2. 解決原理與創新點
  3. 案例與代碼

一、移動滑塊驗證碼樣式背景

移動滑塊驗證碼目的是讓使用者將指定的部分拖動到缺口部分,完成圖形的拼合。目前市場上主要有兩種樣式,一種是無空隙的,換句話說就是拖動的滑塊一開始是處于左側邊緣的,如下圖所示,此類我稱之為無空隙移動滑塊。

Python高效實現滑塊驗證碼自動操縱

另一種則是有空隙的,也即拖動的滑塊一開始不在左側邊緣,而是與左側邊緣存在一定距離的,最常見的就是如下圖所示的企鵝拼圖。

Python高效實現滑塊驗證碼自動操縱

除此樣式的不同之外,更深層次的區別有無原圖與有原圖。熟悉網絡爬蟲技術的coder都知道,在網頁源代碼中是存在一個frame框架來裝驗證碼整個驗證程序,而在解決怎么自動破解這個移動滑塊驗證碼的時候,我們需要下載驗證碼原圖,通過一系列技術發現拖動滑塊與缺口的距離(第二部分會詳解)。而這張原圖就是區別所在,下面為兩個定義的解釋:

無原圖驗證碼:只有帶滑塊的圖,沒有不帶滑塊的原圖

有原圖驗證碼:有不帶滑塊的圖

上面的注釋可能有些云里霧里,那么以無空隙移動滑塊驗證碼舉例,無原圖驗證碼和有原圖驗證碼的圖片如下:

Python高效實現滑塊驗證碼自動操縱

二、解決原理與本文創新點

在每個網站進行表單登錄,如間隔較長時間進行微信登錄就有移動滑塊驗證碼的出現,也有在對多頁進行信息爬取的時為防止是機器操縱而彈出的移動滑塊驗證碼。而這些都需要我們在代碼中判別是否需要進行驗證碼拖動。以微信登錄為例子,由于驗證碼在第一次登錄肯定是會彈出來的,因此,我們只需在代碼中一步一步來即可,不用加判斷條件。

而后便是移動滑塊驗證碼自身的解決問題。換位思考一下,如果不用機器用的是人工,那么我們會根據肉眼的信息自然而然的判斷將滑塊拖動到缺口位置,但是機器是沒有肉眼和判斷力。因此,作為coder,應該給予機器判別能力,能做的即是告訴機器滑塊的位置以及滑塊移動的距離。

在第一部分講解了移動滑塊驗證碼有兩種類別,有空隙和無空隙的。先介紹無空隙情況下如何實現滑塊移動距離的計算。

市面上常用的方式是有邊緣檢測算法,該算法是基于在移動滑塊驗證碼中,缺口的位置四周邊緣有明顯的斷裂痕跡。邊緣檢測算法有Canny算子、Sobel算子等進行計算,大致過程就是將原始的移動滑塊驗證碼圖片進行圖像灰度化、高斯平滑繼而識別到邊緣,整個過程可以借助Python中的opencv庫進行。識別到邊緣后,對缺口和滑塊的輪廓面積做一個限定條件,接著計算滑塊和缺口的質心,進而計算所需位移。不同算子的邊緣檢測算法準確度是不一樣的,普遍都較低且位移誤差大。耗時方面,由于是對圖像進行識別,可想而知其速度是不盡人意的。對于無空隙的移動滑塊驗證碼的情況下,coder僅僅把缺口的質心位置識別出來即可。而對于有空隙的情況下,就需要計算滑塊和缺口的質心,即設定滑塊和缺口的輪廓條件,繼而計算滑塊的移動距離。

市面上除了邊緣檢測算法外,還有一種準確度較高的,也是普遍再用的方法。這種方法是將帶缺口的移動滑塊驗證碼和不到缺口的移動滑塊驗證碼進行RGB像素做差。設定一個閾值并遍歷兩張圖片中的RGB像素,如果相同地方上的差值小于這個閾值那么認為圖像基本是 一致的,反之則是不一致,可以認為是缺口。找到這個缺口后,對于無空隙的驗證碼圖片來說將缺口的質心橫坐標計算出來即是滑動的距離。而對于有空隙的驗證碼圖片來說,就需要有原圖移動滑塊驗證碼圖片和不帶缺口的移動滑塊驗證碼圖片,這樣滑塊和缺口的位置才能通過RGB像素對比得到出來。然而,在大多網頁上是不存在有原圖移動滑塊驗證碼圖片的,需要通過一系列設置才能夠得到,這將在第三部分案例中詳細講到。這個方法可以明顯感覺到準確度是比較大的,但是要求也是比較苛刻,需要有原圖移動滑塊驗證碼圖片。

下面從公式角度理解滑塊移動距離的計算,首先是無空隙的移動滑塊驗證碼,如下圖

Python高效實現滑塊驗證碼自動操縱

可以看到,當coder求出滑塊的質心坐標$C{s}$和缺口的質心坐標$C{g}$后,直接用橫坐標$C{g1}-C{s1}$相減即可。要計算的滑塊移動距離$d$即為$d=C{g1}-C{s1}$,上面講解過其實無空隙的移動滑塊驗證碼在編程中可以偷懶,因為半個滑塊的長度有時在某些網頁中是被允許接受的,也即直接計算缺口的質心$C_{s}$作為移動距離$d$也是可以的。

接著講解有空隙的移動滑塊驗證碼的情況,如下圖:

Python高效實現滑塊驗證碼自動操縱

有空隙的情況就可能復雜點,coder直接利用$d=C{g1}-C{s1}$公式得到滑塊的計算距離是最快的。而如果想要像無空隙移動滑塊驗證碼一樣偷懶的話是不行的,如上圖直接計算質心$C{g}$的橫坐標外,還需要減上空隙的距離、滑塊的一半長度,即$d = C{g1}-d{g}-d{m}$。

  • 創新點
  • 因此,本文在滑塊的移動距離計算方面創新性的提出一種高效且準確度極高的一種方法,借助驗證碼識別平臺---超級鷹。它的技術就是使用目前AI領域最為流行的深度學習進行驗證碼識別。超級鷹提供多種編程語言的調用API,當然就包括本文需要的Python編程語言。下載地址為https://www.chaojiying.com/download/Chaojiying_Python.rar。除此之外,使用者需要在該平臺上注冊賬號。注冊賬號之后方能調用API。超級鷹可以對多種類別的驗證碼進行識別,如數字圖像驗證碼、中文漢字圖像驗證碼、純英文驗證碼、不定長漢字英文數字等,本文需要用到的移動滑塊驗證碼同樣也有。在編程程序中,我們只需在相應的位置上寫上對應的驗證碼類型即可。
  • 利用該方法,可以對移動滑塊驗證碼進行一刀切解決,不用考慮是否有無原圖、有原圖這種情況。如果是采用有空隙的移動滑塊驗證碼圖片,那么就會返回滑塊和缺口的坐標$C{s}$和$C{g}$,coder繼而在利用橫坐標相減即可。
  • 這種方式不僅在耗時上得到成倍的縮減,并且準確度也是極高的。

三、案例與代碼

在了解了無原圖、有原圖、無空隙、有空隙相關特征的滑塊驗證碼后,本文選擇無原圖有空隙的滑塊驗證碼作為案例,選擇小不點搜索網站(https://www.xiaoso.net/)為案例網站,進去以后如下圖所示:

Python高效實現滑塊驗證碼自動操縱

該網站是一個類似于百度、搜狗的這種搜索引擎。它的特點在于,他主要是視頻結果呈現,給出一句關鍵詞后,會給出在知名視頻平臺(B站、youku、qq等)上有關該關鍵詞的視頻。因此,小不點對于經常找相關視頻材料的小伙伴們也是一個大的福利,可以節省下不少的時間。

進去以后,可以看到右上角有個登錄頁面,點進去后呈現如下頁面

Python高效實現滑塊驗證碼自動操縱

由于我們是第一次進入,也即是新用戶,因此,直接進行新用戶注冊即可,無需掃碼,填寫手機號等信息。注冊之后,讀者們可以嘗試登錄,在輸入完用戶名和密碼后會彈出一個驗證碼,該驗證碼就是本文重點講的無原圖有空隙移動滑塊驗證碼。我們需要用Python編程實現自動登錄(自動表單登錄)

Python高效實現滑塊驗證碼自動操縱

Tips:有讀者會問實現這個小不點自動登錄有什么用呢?本文可以給出答案:這個小不點網站僅在本文做一個例子體現,讓讀者可以清洗明了如何使用Python實現自動登錄。在往后實現QQ郵箱自動登錄、爬蟲時遇到反爬蟲就可以舉一反三。

接下來將講解如何在Python中實現小不點網站的自動登錄。

首先,我們需要明確下思路,我們做這個的自動登錄的流程圖應如下所示:

Python高效實現滑塊驗證碼自動操縱
  • 登錄頁面解析

其實整個登錄頁面是很比較簡潔的,我們讓機器實現自動輸入英文用戶名、密碼、點擊提交即可。整個過程只有三步,那如何讓機器找到填寫與點擊的位置呢,我們就需要找到網頁的源代碼,在源代碼中找到三個元素對應的相關代碼即可。

如何打開網頁源代碼?在所在頁面按F12即可,然后同時按住ctrl+shift+C即可快捷的進入到鼠標拖動模式,該模式下利用鼠標點擊即可到達相應位置的源代碼,比如點擊"英文用戶名",效果如圖下所示

Python高效實現滑塊驗證碼自動操縱

可以看到"英文用戶名"元素的類名為input,是一個輸入文本類型,那么如何取出其代碼呢?其實這里所說的代碼只是籠統的概念,本質上是讓機器識別出元素的位置。那么識別元素的位置在網頁中有許多方式,例如利用id去導航,class類去導航、css等。本文則主要選擇xpath去導航,xpath可以理解為機器(Python中的selenium工具)使用路徑表達式在 XML 文檔中進行導航。除此之外,本文還少量用到name屬性,如上面那張圖,name=“username”在該網頁中是有且只有一個的,那么就可以直接同name進行導航。

具體怎么得到這些元素的相關屬性實現導航呢,很簡單,在右側對應代碼中鼠標右鍵點擊,找到copy,選擇"copy xpath"即可。

同理,英文用戶名、密碼、提交均可以使用上述方法。此外,點擊提交后會彈出移動滑塊驗證碼。這個驗證碼在實現滑塊的拖動與點擊依舊是上述的xpath元素定位方法。但稍有不同的是,需要先切換到驗證碼所在frame中。frame為框,可以理解為在一個網頁中嵌套的頁面,frame不是獨立的頁面而是原本網頁中一個產物。因此,在編程的時候需要注意,要從原本的frame中切換到驗證碼所在的frame,不然會報錯。

  • Python操縱
  • 在利用Python實現小不點搜索網表單自動登錄時,需要用到一個非常經典的網站自動化測試庫---selenium。這個庫支持各種瀏覽器如Google、Firebox等主流頁面。不僅如此,還支持Windows、Linus等系統。
  • 安裝完selenium以后,就需要學習如何使用并結合"登錄頁面解析"部分實現元素定位。相關代碼如下:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains import time
from selenium.webdriver.support.ui import WebDriverWait
from chaojiying import Chaojiying_Client
    # 啟動瀏覽器
    def Launch_browser(self): self.driver = webdriver.Chrome() self.wait = WebDriverWait(self.driver, 10, 0.5) self.driver.get(self.url)
        account = self.account
        pwd = self.pwd self.driver.find_element_by_name('username').send_keys(account) self.driver.find_element_by_name('password').send_keys(pwd) self.driver.find_element_by_xpath(self.enter).click()
        # 等待className為geetest_slider_button的元素在元素表中出現
        time.sleep(2)

這段代碼是使用類定義編寫的,首先引入相關庫。

webdriver.Chrome()這句函數是調出Google瀏覽器,比如在anaconda中的spyder編譯器,會彈出一個Google瀏覽器頁面。這相當于完成機器自動打開瀏覽器這一操作。接下來就是讓機器跳轉到小不點搜索網站,用的是self.driver.get(self.url)這一函數。self.url這里指的是小不點搜索網站的網址。

跳轉后就會到熟悉的登錄界面,在界面中如何導航到英文用戶名和密碼對應的位置并輸入進去呢?代碼中

account = self.account ##輸入小不點注冊的賬號 pwd = self.pwd #輸入小不點注冊的密碼 self.driver.find_element_by_name('username').send_keys(account) # 找到賬號位置并給予信息 self.driver.find_element_by_name('password').send_keys(pwd) #找到密碼位置并給予信息 self.driver.find_element_by_xpath(self.enter).click() #模擬點擊提交按鈕

便是導航到元素對應位置與點擊提交的操縱,可以看到本文使用name元素定位的,這也應征了上一部分所說,'username'和'password'在該頁面是獨立存在。最后的代碼time.sleep(2)是防止網速過慢導致滑塊驗證碼出現延遲而跟不上機器識別的節奏導致的問題出現。

接下來就是移動滑塊驗證碼的破解,破解當然需要超級鷹,但是超級鷹服務的引入下一部分在說明。而破解的前提是要獲取移動滑塊驗證碼的圖片,這里本文將利用selenium庫中的截屏功能,將移動滑塊驗證碼的圖片整一張保存至本地中。代碼如下

# 移動滑塊驗證碼截圖 def get_picture(self): self.driver.switch_to_frame(self.frame) #一定要轉到驗證碼的框,才能定位?。?! self.slider = self.driver.find_element_by_xpath(self.slider_xpath) ## 先將滑塊隱藏,獲取原圖,在截圖,在復原 self.driver.execute_script("document.getElementsByClassName('{}')[0].style['display'] = 'none'".format(self.gap_xpath)) self.driver.find_element_by_xpath('//*[@id="slideBgWrap"]').screenshot(self.file_path) self.driver.find_element_by_xpath(self.img_xpath).screenshot(self.file_path2) self.driver.execute_script("document.getElementsByClassName('{}')[0].style['display'] = 'block'".format(self.gap_xpath))

首先依舊采用類與對象的寫法,第一行代碼是將frame轉到移動滑塊驗證碼所在的框中,第二行則是通過xpath路徑導航到滑塊的地方。接著則是驗證碼截圖部分重要的地方,前面講了該案例是解決無原圖有空隙的移動滑塊驗證碼。如果整個過程交給了超級鷹那么無原圖有空隙這兩個問題變迎刃而解。但是,如果采用市面上常用的方法呢,那么無原圖怎么解決呢?第3行到最后一行代碼就是答案。同樣是利用selenium庫的功能,首先通過多次試驗,作者發現在網頁源代碼上做特定的修改就會使驗證碼圖像變回原來的圖像,不會帶缺口的。修改方式就是在
document.getElementsByClassName('{}')[0]
處賦予沒有缺口屬性.style['display'] = 'none'。賦予之后就會呈現原圖,接著利用xpath導航至驗證碼原圖的位置并screenshot截圖一下即可完成移動滑塊驗證碼圖片的本地保存。最后復原驗證碼圖片,在修改處改為.style['display'] = 'block',即可重新出現缺口。下載下來的圖片如下圖所示(tips:由于每一次登錄的驗證碼圖片都不一致,這里展現實驗時的一次。)

Python高效實現滑塊驗證碼自動操縱
  • 超級鷹服務引入

得到了驗移動滑塊驗證碼圖片之后,我們需要計算滑塊到缺口的距離,這時候使用Chaojiying無疑是高效實現。

在超級鷹平臺上有一個名為"Chaojiying"的Python API接口,是平臺寫好并讓Python user來直接調用的,下載地址為:
https://www.chaojiying.com/download/Chaojiying_Python.rar。而在main主程序上我們只需要在同一路徑下實現該代碼即可

from chaojiying import Chaojiying_Client

引入該服務后,需要上傳在超級鷹平臺注冊的賬號密碼,還有需要識別的驗證碼圖片。具體代碼如下:

# 超級鷹 def cjy(self): # 用戶中心>>軟件ID 生成一個替換 910001 self.chaojiying = Chaojiying_Client('', '', '') # chaojiying = Chaojiying_Client('超級鷹用戶名', '超級鷹密碼', '910001') # 本地圖片文件路徑 來替換 a.jpg 有時WIN系統須要// im = open('./img/code_picture2.png', 'rb').read() #驗證碼圖片存放位置 # 9101 驗證碼類型  官方網站>>價格體系 3.4+版 print 后要加() # 咨詢了一下滑動驗證碼是選擇9101 re = self.chaojiying.PostPic(im, 9101) print('兩個坐標') print(re) # 減去一半滑塊長度 self.diff = int(re['pic_str'].split(',')[0]) self.distance = int(re['pic_str'].split('|')[1].split(',')[0]) - self.diff print(self.distance) self.im_id = re['pic_id'] print(self.im_id)

解析:首先讀者需要在Chaojiying_client這句函數里面寫上相關的用戶名、密碼和軟件ID。其次以二進制格式讀取移動滑塊驗證碼圖片并使用Chaojiying內置函數Postpic上傳至平臺。這樣平臺就會返回我們滑塊到缺口gap的坐標,我們利用兩坐標相減即可得到路徑。注意:在得到路徑上應該減去一半滑塊長度,在第二部分已經講解為何減去一半滑塊長度。

在得到滑塊移動的路徑后,更謹慎的我們還需要賦予滑塊一個速度,以防止網站發現是機器人操縱。具體代碼如下:

# 獲取移動軌跡 def get_track(self): self.track = []
        mid = self.distance * 3 / 5 current = 0 t = 0.2 v = 0 while current < self.distance: if current < mid: a = 8 else: a = -12 v0 = v
            v = v0 + a * t
            move = v * t + 1 / 2 * a * t * t
            current += move self.track.append(round(move))
        print(self.track) # 模擬移動 def move(self): self.track = self.track 
        ActionChains(self.driver).click_and_hold(self.slider).perform() for x in self.track: ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform()
        time.sleep(2)
        ActionChains(self.driver).release().perform() self.slider.click()

第一個def類---get_track就是定義滑塊的移動每0.2秒的移動距離。本文定義為在移動路徑的$frac{2}{5}$路徑之前加速度為8,即做加速直線運動。后半程的加速度為-12即做減速直線運動。結合速度公式和位移公式即可得到每一步滑塊需要走多遠。

最后使用selenium庫中的懸停鼠標工具ActionChains拖拽住滑塊,遍歷每一步的步長,講滑塊移動到缺口位置。

  • 總代碼

可以看到上述的代碼時以類方式封裝的,因此介紹上使用者如何運行代碼,首先是主程序main

from no_img import scratch_main
url = 'https://www.xiaoso.net/m/member/action/login'
username = '' #輸入小不點賬號 password = '' #輸入小不點密碼 enter_xpath = '//*[@id="TencentCaptcha"]'
frame = 'tcaptcha_iframe'
slider_xpath = '//*[@id="tcaptcha_drag_thumb"]'
gap_xpath = 'tc-jpp-img unselectable'
img_xpath = '//*[@id="slideBgWrap"]'
process = scratch_main(url,username,password,enter_xpath,frame,slider_xpath,gap_xpath,img_xpath)
process.main()

這個需要使用者在username和password上輸入自己在小不點上注冊的賬號密碼,接著是no_img程序,

'''
無原圖滑塊驗證碼案例
author:henry
''' from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from PIL import Image
from chaojiying import Chaojiying_Client class scratch_main(): def __init__(self,url,username,password,enter_xpath,frame,slider_xpath,gap_xpath,img_xpath): self.url = url self.file_path = './img/code_picture.png' self.file_path2 = './img/code_picture2.png' self.distance = 0 self.key = 0 self.account = username self.pwd = password self.enter = enter_xpath self.frame = frame self.slider_xpath = slider_xpath self.gap_xpath = gap_xpath self.img_xpath = img_xpath # 啟動瀏覽器 def Launch_browser(self): self.driver = webdriver.Chrome() self.wait = WebDriverWait(self.driver, 10, 0.5) self.driver.get(self.url)
        account = self.account
        pwd = self.pwd
        time.sleep(2) self.driver.find_element_by_name('username').send_keys(account) self.driver.find_element_by_name('password').send_keys(pwd) self.driver.find_element_by_xpath(self.enter).click()
        time.sleep(2) self.driver.switch_to_frame(self.frame) #一定要轉到驗證碼的框,才能定位?。?! self.slider = self.driver.find_element_by_xpath(self.slider_xpath) # 截圖 def get_picture(self): ## 先將滑塊隱藏,獲取原圖,在截圖,在復原 self.driver.find_element_by_xpath(self.img_xpath).screenshot(self.file_path2) self.driver.execute_script("document.getElementsByClassName('{}')[0].style['display'] = 'block'".format(self.gap_xpath)) # 分割截圖獲取驗證碼圖片,由于使用超級鷹,所以直接用上面截圖驗證碼部分即可,不用截圖缺口 def crop_picture(self):
        pass # 超級鷹 def cjy(self): # 用戶中心>>軟件ID 生成一個替換 910001 self.chaojiying = Chaojiying_Client('', '', '') # chaojiying = Chaojiying_Client('超級鷹用戶名', '超級鷹密碼', '910001') # 本地圖片文件路徑 來替換 a.jpg 有時WIN系統須要// im = open('./img/code_picture2.png', 'rb').read()
        re = self.chaojiying.PostPic(im, 9202)
        print('兩個坐標')
        print(re) # print(re['pic_str']) # 減去一半滑塊長度 self.diff = int(re['pic_str'].split(',')[0]) self.distance = int(re['pic_str'].split('|')[1].split(',')[0]) - self.diff
        print(self.distance) self.im_id = re['pic_id']
        print(self.im_id) # 獲取軌跡 def get_track(self): self.track = []
        mid = self.distance * 2 / 5 current = 0 t = 0.2 v = 0 while current < self.distance: if current < mid: a = 8 else: a = -12 v0 = v
            v = v0 + a * t
            move = v * t + 1 / 2 * a * t * t
            current += move self.track.append(round(move))
        print(self.track) # 模擬移動 def move(self): self.track = self.track 
        ActionChains(self.driver).click_and_hold(self.slider).perform() for x in self.track: ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform()
        time.sleep(2)
        ActionChains(self.driver).release().perform() self.slider.click() def check(self):
        pass # 關閉瀏覽器 def quit(self):
        time.sleep(5) self.driver.quit() # main方法 def main(self): self.Launch_browser() self.get_picture() self.crop_picture() self.cjy() self.get_track() self.move() self.check() if __name__ == '__main__':
    ma = scratch_main()
    ma.main()

這里需要使用者在cjy類中輸入自己在超級鷹上注冊的賬號密碼和軟件ID。此外,使用者需要把main、Chaojiying、no_img三個程序放到一個相同路徑下。

數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢