【0基礎(chǔ)學(xué)爬蟲】爬蟲基礎(chǔ)之自動(dòng)化工具 DrissionPage 的使用

640.png

概述

前三期文章中已經(jīng)介紹到了 Selenium 與 Playwright 、Pyppeteer 的使用方法,它們的功能都非常強(qiáng)大。而本期要講的 DrissionPage 更為獨(dú)特,強(qiáng)大,而且使用更為方便,目前檢測(cè)少,強(qiáng)烈推薦!??!

這里推薦觀看十一姐 B 站 DrissionPage 系列視頻,很詳細(xì):

合集·爬蟲自動(dòng)化 DrissionPage 實(shí)戰(zhàn)案例:
https://space.bilibili.com/308704191/channel/collectiondetail?sid=1947582

DrissionPage 相關(guān)資料:

官方文檔:https://www.drissionpage.cn
Drissionpage “姊妹庫(kù)”:https://gitee.com/haiyang0726/SaossionPage

DrissionPage 的使用

介紹

DrissionPage 是一個(gè)基于 python 的網(wǎng)頁(yè)自動(dòng)化工具。它既能控制瀏覽器,也能收發(fā)數(shù)據(jù)包,還能把兩者合而為一??杉骖櫈g覽器自動(dòng)化的便利性和 requests 的高效率。它功能強(qiáng)大,內(nèi)置無(wú)數(shù)人性化設(shè)計(jì)和便捷功能。它的語(yǔ)法簡(jiǎn)潔而優(yōu)雅,代碼量少,對(duì)新手友好。

  • 支持系統(tǒng):Windows、Linux、Mac;

  • python 版本:3.6 及以上;

  • 支持應(yīng)用:Chromium 內(nèi)核瀏覽器(如 Chrome、Edge),electron 應(yīng)用;

image-20240605165511013.png

特性

強(qiáng)大的自研內(nèi)核

本庫(kù)采用全自研的內(nèi)核,內(nèi)置了無(wú)數(shù)實(shí)用功能,對(duì)常用功能作了整合和優(yōu)化,對(duì)比 selenium,有以下優(yōu)點(diǎn):

  • 無(wú) webdriver 特征;
  • 無(wú)需為不同版本的瀏覽器下載不同的驅(qū)動(dòng);
  • 運(yùn)行速度更快;
  • 可以跨 iframe 查找元素,無(wú)需切入切出;
  • 把 iframe 看作普通元素,獲取后可直接在其中查找元素,邏輯更清晰;
  • 可以同時(shí)操作瀏覽器中的多個(gè)標(biāo)簽頁(yè),即使標(biāo)簽頁(yè)為非激活狀態(tài),無(wú)需切換;
  • 可以直接讀取瀏覽器緩存來(lái)保存圖片,無(wú)需用 GUI 點(diǎn)擊另存;
  • 可以對(duì)整個(gè)網(wǎng)頁(yè)截圖,包括視口外的部分(90 以上版本瀏覽器支持);
  • 可處理非 open 狀態(tài)的 shadow-root。

亮點(diǎn)功能

除了以上優(yōu)點(diǎn),本庫(kù)還內(nèi)置了無(wú)數(shù)人性化設(shè)計(jì)。

  • 極簡(jiǎn)的語(yǔ)法規(guī)則,集成大量常用功能,代碼更優(yōu)雅;
  • 定位元素更加容易,功能更強(qiáng)大穩(wěn)定;
  • 無(wú)處不在的等待和自動(dòng)重試功能。使不穩(wěn)定的網(wǎng)絡(luò)變得易于控制,程序更穩(wěn)定,編寫更省心;
  • 提供強(qiáng)大的下載工具。操作瀏覽器時(shí)也能享受快捷可靠的下載功能;
  • 允許反復(fù)使用已經(jīng)打開(kāi)的瀏覽器。無(wú)需每次運(yùn)行從頭啟動(dòng)瀏覽器,調(diào)試超方便;
  • 使用 ini 文件保存常用配置,自動(dòng)調(diào)用,提供便捷的設(shè)置,遠(yuǎn)離繁雜的配置項(xiàng);
  • 內(nèi)置 lxml 作為解析引擎,解析速度成幾個(gè)數(shù)量級(jí)提升;
  • 使用 POM 模式封裝,可直接用于測(cè)試,便于擴(kuò)展;
  • 高度集成的便利功能,從每個(gè)細(xì)節(jié)中體現(xiàn);
  • 還有很多細(xì)節(jié),這里不一一列舉,歡迎實(shí)際使用中體驗(yàn)。

安裝升級(jí)

# 安裝
pip install DrissionPage
 
# 升級(jí)最新穩(wěn)定版
pip install DrissionPage --upgrade
 
# 指定版本升級(jí)
pip install DrissionPage==4.0.0b17
  • 如何在無(wú)界面 Linux 使用:

CentOS 請(qǐng)參考這篇文章:

linux 部署說(shuō)明:https://blog.csdn.net/sinat_39327967/article/details/132181129

Ubuntu 請(qǐng)參考這篇文章:

DrissionPage 在 Ubuntu Linux 的使用:https://zhuanlan.zhihu.com/p/674687748

使用

訪問(wèn)網(wǎng)頁(yè)

from DrissionPage import ChromiumPage, ChromiumOptions

co = ChromiumOptions().set_paths(browser_path=r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
# 1、設(shè)置無(wú)頭模式:co.headless(True)
# 2、設(shè)置無(wú)痕模式:co.incognito(True)
# 3、設(shè)置訪客模式:co.set_argument('--guest')
# 4、設(shè)置請(qǐng)求頭user-agent:co.set_user_agent()
# 5、設(shè)置指定端口號(hào):co.set_local_port(7890)
# 6、設(shè)置代理:co.set_proxy('http://localhost:1080')
page = ChromiumPage(co)

page.get('https://gitee.com/login', retry=3, timeout=15, interval=2)

# 定位到賬號(hào)文本框,獲取文本框元素
ele = page.ele('#user_login')
# 輸入對(duì)文本框輸入賬號(hào)
ele.input('您的賬號(hào)')
# 定位到密碼文本框并輸入密碼
page.ele('#user_password').input('您的密碼')
# 點(diǎn)擊登錄按鈕
page.ele('@value=登 錄').click()

獲取瀏覽器路徑的方法:

  • 這里的瀏覽器路徑不一定是 Chrome,Edge 等 Chromium 內(nèi)核的瀏覽器都可以;
  • 打開(kāi)瀏覽器,在地址欄輸入 chrome://version(Edge 輸入 edge://version),回車
    如圖所示,紅框中就是要獲取的路徑:
image-20240605171438691.png
  • 此法不限于 Windows,有界面的 Linux 也是這樣取路徑。
  • get()

該方法用于跳轉(zhuǎn)到一個(gè)網(wǎng)址。當(dāng)連接失敗時(shí),程序會(huì)進(jìn)行重試:

1.png

獲取查找元素

本庫(kù)提供一套簡(jiǎn)潔易用的語(yǔ)法,用于快速定位元素,并且內(nèi)置等待功能、支持鏈?zhǔn)讲檎?,減少了代碼的復(fù)雜性。

同時(shí)也兼容 css selector、xpath、selenium 原生的 loc 元組。

定位元素大致分為三種方法:

  • 在頁(yè)面或元素內(nèi)查找子元素;
  • 根據(jù) DOM 結(jié)構(gòu)相對(duì)定位;
  • 根據(jù)頁(yè)面布局位置相對(duì)定位;
  • xpath 方式:
# 輸入
page.ele('xpath://input[@id="bindMobileFree"]').input("123456789")
# 點(diǎn)擊
page.ele('x://span[@class="getYZM_btn"]').click()
  • 其他方式:
from DrissionPage import SessionPage

page = SessionPage()
page.get('https://gitee.com/explore')

# 獲取包含“全部推薦項(xiàng)目”文本的 ul 元素
ul_ele = page.ele('tag:ul@@text():全部推薦項(xiàng)目')  

# 獲取該 ul 元素下所有 a 元素
titles = ul_ele.eles('tag:a')  

# 遍歷列表,打印每個(gè) a 元素的文本
for i in titles:  
    print(i.text)
foot = page.ele('#footer-left')  # 用 id 查找元素
first_col = foot.ele('css:>div')  # 使用 css selector 在元素的下級(jí)中查找元素(第一個(gè))
lnk = first_col.ele('text:命令學(xué)')  # 使用文本內(nèi)容查找元素
text = lnk.text  # 獲取元素文本
href = lnk.attr('href')  # 獲取元素屬性值

print(text, href, '\n')

# 簡(jiǎn)潔模式串聯(lián)查找
text = page('@id:footer-left')('css:>div')('text:命令學(xué)').text
print(text)

等待

  • ??? 頁(yè)面對(duì)象的等待方法:

    • ?? wait.load_start() :此方法用于等待頁(yè)面進(jìn)入加載狀態(tài);

      • 注意

        get()已內(nèi)置等待加載開(kāi)始,后無(wú)須跟wait.load_start();

    • ?? wait.doc_loaded():此方法用于等待頁(yè)面文檔加載完成;

      • 注意
        • 此功能僅用于等待頁(yè)面主 document 加載,不能用于等待 js 加載的變化;
        • 除非load_modeNone,get()方法已內(nèi)置等待加載完成,后面無(wú)須添加等待;
    • ?? wait.eles_loaded():此方法用于等待元素被加載到 DOM;

    • ?? wait.ele_displayed():此方法用于等待一個(gè)元素變成顯示狀態(tài);

    • ?? wait.ele_hidden():此方法用于等待一個(gè)元素變成隱藏狀態(tài);

    • ?? wait.ele_deleted():此方法用于等待一個(gè)元素被從 DOM 中刪除;

    • ?? wait.download_begin():此方法用于等待下載開(kāi)始;

    • ?? wait.upload_paths_inputted():此方法用于等待自動(dòng)填寫上傳文件路徑;

    • ?? wait.new_tab():此方法用于等待新標(biāo)簽頁(yè)出現(xiàn);

    • ?? wait.title_change():此方法用于等待 title 變成包含或不包含指定文本;

    • ?? wait.url_change():此方法用于等待 url 變成包含或不包含指定文本。 比如有些網(wǎng)站登錄時(shí)會(huì)進(jìn)行多重跳轉(zhuǎn),url 發(fā)生多次變化,可用此功能等待到達(dá)最終需要的頁(yè)面;

    • ?? wait.alert_closed():此方法用于等待彈出框被關(guān)閉;

    • ?? wait():此方法用于等待若干秒;

  • ??? 元素對(duì)象的等待方法

    • ?? wait.displayed():此方法用于等待元素從隱藏狀態(tài)變成顯示狀態(tài);

    • ?? wait.hidden():此方法用于等待元素從顯示狀態(tài)變成隱藏狀態(tài);

    • ?? wait.deleted():此方法用于等待元素被從 DOM 刪除;

    • ?? wait.covered():此方法用于等待元素被其它元素覆蓋;

    • ?? wait.not_covered():此方法用于等待元素不被其它元素覆蓋;

    • ?? wait.enabled():此方法用于等待元素變?yōu)榭捎脿顟B(tài);

    • ?? wait.disabled():此方法用于等待元素變?yōu)椴豢捎脿顟B(tài);

    • ?? wait.stop_moving():此方法用于等待元素運(yùn)動(dòng)結(jié)束;

    • ?? wait.clickable():此方法用于等待元素可被點(diǎn)擊;

    • ?? wait.disabled_or_deleted():此方法用于等待元素變?yōu)椴豢捎没虮粍h除;

    • ?? wait():此方法用于等待若干秒。

監(jiān)聽(tīng)網(wǎng)絡(luò)數(shù)據(jù)

  • 注意:要先啟動(dòng)監(jiān)聽(tīng),再執(zhí)行動(dòng)作,listen.start() 之前的數(shù)據(jù)包是獲取不到的;
  • 等待并獲取:
  • 等待并獲?。?/li>
from DrissionPage import ChromiumPage

page = ChromiumPage()
page.get('https://gitee.com/explore/all')  # 訪問(wèn)網(wǎng)址,這行產(chǎn)生的數(shù)據(jù)包不監(jiān)聽(tīng)

page.listen.start('gitee.com/explore')  # 開(kāi)始監(jiān)聽(tīng),指定獲取包含該文本的數(shù)據(jù)包(部分url)
for _ in range(5):
    page('@rel=next').click()  # 點(diǎn)擊下一頁(yè)
    res = page.listen.wait()  # 等待并獲取一個(gè)數(shù)據(jù)包
    print(res.url)  # 輸出數(shù)據(jù)包url
    print(res.response.headers)  # 輸出響應(yīng)頭
    print(res.response.statusText)  # 輸出響應(yīng)狀態(tài)碼
    print(res.response.body)  # 輸出響應(yīng)內(nèi)容
  • 實(shí)時(shí)獲?。?/li>
from DrissionPage import ChromiumPage

page = ChromiumPage()
page.listen.start('gitee.com/explore')  # 開(kāi)始監(jiān)聽(tīng),指定獲取包含該文本的數(shù)據(jù)包
page.get('https://gitee.com/explore/all')  # 訪問(wèn)網(wǎng)址

i = 0
for packet in page.listen.steps():
    print(packet.url)  # 打印數(shù)據(jù)包url
    page('@rel=next').click()  # 點(diǎn)擊下一頁(yè)
    i += 1
    if i == 5:
        break

動(dòng)作鏈

  • ?? 使用方法
  • ?? 使用內(nèi)置 actions 屬性
```python
from DrissionPage import ChromiumPage

page = ChromiumPage()
page.get('https://www.baidu.com')
page.actions.move_to('#kw').click().type('DrissionPage')
page.actions.move_to('#su').click()
```

*   ?? 使用新對(duì)象

```python
from DrissionPage import ChromiumPage
from DrissionPage.common import Actions

page = ChromiumPage()
ac = Actions(page)
page.get('https://www.baidu.com')
ac.move_to('#kw').click().type('DrissionPage')
ac.move_to('#su').click()
```

*   ?? 操作方式

```python
ac.move_to(ele).click().type('some text')
```
  • ?? 移動(dòng)鼠標(biāo)

    • ??move_to():此方法用于移動(dòng)鼠標(biāo)到元素中點(diǎn),或頁(yè)面上的某個(gè)絕對(duì)坐標(biāo);
    • ?? move():此方法用于使鼠標(biāo)相對(duì)當(dāng)前位置移動(dòng)若干距離;
    • ?? up():此方法用于使鼠標(biāo)相對(duì)當(dāng)前位置向上移動(dòng)若干距離;
    • ?? down():此方法用于使鼠標(biāo)相對(duì)當(dāng)前位置向下移動(dòng)若干距離;
    • ?? left():此方法用于使鼠標(biāo)相對(duì)當(dāng)前位置向左移動(dòng)若干距離;
    • ?? right():此方法用于使鼠標(biāo)相對(duì)當(dāng)前位置向右移動(dòng)若干距離。
  • ?? 鼠標(biāo)按鍵

    • ?? click():此方法用于單擊鼠標(biāo)左鍵,單擊前可先移動(dòng)到元素上;
    • ?? r_click():此方法用于單擊鼠標(biāo)右鍵,單擊前可先移動(dòng)到元素上;
    • ?? m_click():此方法用于單擊鼠標(biāo)中鍵,單擊前可先移動(dòng)到元素上;
    • ?? db_click():此方法用于雙擊鼠標(biāo)左鍵,雙擊前可先移動(dòng)到元素上;
    • ?? hold():此方法用于按住鼠標(biāo)左鍵不放,按住前可先移動(dòng)到元素上;
    • ?? release():此方法用于釋放鼠標(biāo)左鍵,釋放前可先移動(dòng)到元素上;
    • ?? r_hold():此方法用于按住鼠標(biāo)右鍵不放,按住前可先移動(dòng)到元素上;
    • ?? r_release():此方法用于釋放鼠標(biāo)右鍵,釋放前可先移動(dòng)到元素上;
    • ?? m_hold():此方法用于按住鼠標(biāo)中鍵不放,按住前可先移動(dòng)到元素上;
    • ?? m_release():此方法用于釋放鼠標(biāo)中鍵,釋放前可先移動(dòng)到元素上。
  • ?? 滾動(dòng)滾輪

    • ?? scroll():此方法用于滾動(dòng)鼠標(biāo)滾輪,滾動(dòng)前可先移動(dòng)到元素上;
  • ?? 鍵盤按鍵和文本輸入

    • ?? key_down():此方法用于按下鍵盤按鍵。非字符串按鍵(如 ENTER)可輸入其名稱,也可以用 Keys 類獲??;
    • ?? key_up():此方法用于提起鍵盤按鍵。非字符串按鍵(如 ENTER)可輸入其名稱,也可以用 Keys 類獲取;
    • ?? input():此方法用于輸入一段文本或多段文本,也可輸入組合鍵。多段文本或組合鍵用列表傳入;
    • ?? type():此方法用于以按鍵盤的方式輸入一段或多段文本。也可輸入組合鍵。type()input()區(qū)別在于前者模擬按鍵輸入,逐個(gè)字符按下和提起,后者直接輸入一整段文本。
  • ?? 等待

    • ?? wait():此方法用于等待若干秒;
  • ?? 屬性

    • ?? owner:此屬性返回使用此動(dòng)作鏈的頁(yè)面對(duì)象;
    • ?? curr_x:此屬性返回當(dāng)前光標(biāo)位置的 x 坐標(biāo);
    • ?? curr_y:此屬性返回當(dāng)前光標(biāo)位置的 y 坐標(biāo)。
  • ?? 示例

    • ?? 模擬輸入 ctrl+a
    from DrissionPage import ChromiumPage
    from DrissionPage.common import Keys, Actions
    
    # 創(chuàng)建頁(yè)面
    page = ChromiumPage()
    # 創(chuàng)建動(dòng)作鏈對(duì)象
    ac = Actions(page)
    
    # 鼠標(biāo)移動(dòng)到<input>元素上
    ac.move_to('tag:input')
    # 點(diǎn)擊鼠標(biāo),使光標(biāo)落到元素中
    ac.click()
    # 按下 ctrl 鍵
    ac.key_down(Keys.CTRL)
    # 輸入 a
    ac.type('a')
    # 提起 ctrl 鍵
    ac.key_up(Keys.CTRL)
    

    鏈?zhǔn)綄懛ǎ?/p>

    ac.click('tag:input').key_down(Keys.CTRL).type('a').key_up(Keys.CTRL)
    

    更簡(jiǎn)單的寫法:

    ac.click('tag:input').type(Keys.CTRL_A)
    
    • ?? 拖拽元素

    把一個(gè)元素向右拖拽 300 像素:

    from DrissionPage import ChromiumPage
    from DrissionPage.common import Actions
    
    # 創(chuàng)建頁(yè)面
    page = ChromiumPage()
    # 創(chuàng)建動(dòng)作鏈對(duì)象
    ac = Actions(page)
    
    # 左鍵按住元素
    ac.hold('#div1')
    # 向右移動(dòng)鼠標(biāo)300像素
    ac.right(300)
    # 釋放左鍵
    ac.release()
    

    把一個(gè)元素拖拽到另一個(gè)元素上:

    ac.hold('#div1').release('#div2')
    
  • ?? 頁(yè)面對(duì)象內(nèi)置動(dòng)作鏈

from DrissionPage import ChromiumPage

page = ChromiumPage()
page.actions.move_to((300, 500)).hold().move(300).release()

標(biāo)簽頁(yè)操作

?? 注意:可以對(duì)多標(biāo)簽頁(yè)操作, 即可實(shí)現(xiàn)并發(fā)自動(dòng)化。

  • ??? 標(biāo)簽頁(yè)總覽

    • ?? tabs_count:此屬性返回標(biāo)簽頁(yè)數(shù)量。
    • ?? tab_ids:此屬性以list方式返回所有標(biāo)簽頁(yè) id。
  • ??? 新建標(biāo)簽頁(yè)

    • ?? new_tab():該方法用于新建一個(gè)標(biāo)簽頁(yè),該標(biāo)簽頁(yè)在最后面。只有 Page 對(duì)象擁有此方法。
  • ??? 獲取標(biāo)簽頁(yè)對(duì)象

    • ?? get_tab():此方法用于獲取一個(gè)標(biāo)簽頁(yè)對(duì)象。可指定標(biāo)簽頁(yè)序號(hào)、id、標(biāo)題、url、類型等條件用于檢索。當(dāng)id_or_num不為None時(shí),其它參數(shù)無(wú)效。當(dāng)所有參數(shù)都為None時(shí),獲取 Page 對(duì)象控制的標(biāo)簽頁(yè)的 Tab 對(duì)象。title、urltab_type三個(gè)參數(shù)是與關(guān)系。只有 Page 對(duì)象擁有此方法。
    • ?? get_tabs():此方法用于查找符合條件的 tab 對(duì)象
  • ??? 使用多例

    from DrissionPage import ChromiumPage
    from DrissionPage.common import Settings
    
    page = ChromiumPage()
    page.new_tab()
    page.new_tab()
    
    # 未啟用多例:
    tab1 = page.get_tab(1)
    tab2 = page.get_tab(1)
    print(id(tab1), id(tab2))
    
    # 啟用多例:
    Settings.singleton_tab_obj = False
    tab1 = page.get_tab(1)
    tab2 = page.get_tab(1)
    print(id(tab1), id(tab2))
    
  • ??? 關(guān)閉和重連

    • ?? close()
    • ?? disconnect()
    • ?? reconnect()
    • ?? close_tabs()
  • ??? 激活標(biāo)簽頁(yè)

    • ?? set.tab_to_front()
    • ?? set.activate()
  • ??? 多標(biāo)簽頁(yè)協(xié)同

截圖和錄像

??? 頁(yè)面截圖

# 對(duì)整頁(yè)截圖并保存
page.get_screenshot(path='tmp', name='pic.jpg', full_page=True)

??? 元素截圖

img = page('tag:img')
img.get_screenshot()
bytes_str = img.get_screenshot(as_bytes='png')  # 返回截圖二進(jìn)制文本

??? 頁(yè)面錄像

from DrissionPage import ChromiumPage

page = ChromiumPage()
page.screencast.set_save_path('video')  # 設(shè)置視頻存放路徑
page.screencast.set_mode.video_mode()  # 設(shè)置錄制
page.screencast.start()  # 開(kāi)始錄制
page.wait(3)
page.screencast.stop()  # 停止錄制

執(zhí)行 JS 語(yǔ)句

page.run_js(f'localStorage.setItem("__user_token.v3",`{token}`)')

page.run_js(f'localStorage.setItem("__user_info",`{token}`)')

cookies_set = ""
cookies_set += f'document.cookie=`__user_token.v3={token}; path=/;domain=i.shengcaiyoushu.com;`;'

page.run_js(cookies_set)

反檢測(cè)

在 Selenium、Playwright 、Playwright 的使用中,我們講到了自動(dòng)化工具容易被網(wǎng)站檢測(cè),也提供了一些繞過(guò)檢測(cè)的方案。這里我們介紹一下 DrissionPage 的反檢測(cè)方案。

https://bot.sannysoft.com 為例,我們分別測(cè)試正常模式與無(wú)頭模式下的檢測(cè)結(jié)果:

  • 正常模式:
image-20240605142322383.png
  • 無(wú)頭模式:
image-20240605164000018.png

可以發(fā)現(xiàn),我們沒(méi)有做任何反檢測(cè)的操作,都不會(huì)被檢測(cè)到,就連使用無(wú)頭模式也只有 userAgent 有問(wèn)題,不過(guò)我們 co.set_user_agent() 設(shè)置一下就可以了,雖然這些只是最基本的檢測(cè)機(jī)制,但也夠用了。

總結(jié)

DrissionPage 語(yǔ)法簡(jiǎn)潔,使用方便,底層基于 CDP 協(xié)議,擁有較強(qiáng)的反檢測(cè)機(jī)制,目前不需要做任何反檢測(cè)的操作就可以繞過(guò)國(guó)內(nèi)外絕大多數(shù)的網(wǎng)站自動(dòng)化檢測(cè),包含但不限于 (xx 驗(yàn)證碼、某數(shù)、5s)。 還有很多強(qiáng)大的功能這里沒(méi)法一一展示,強(qiáng)烈推薦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容