寫在最前
程序是為人類服務(wù)的,最近正好身邊小伙伴們?cè)谧銮蛞律猓?dāng)然是去nikenba專區(qū)購(gòu)買了,可是有些熱門球衣發(fā)布幾分鐘就被搶完,有些折扣球衣也是很快就被搶售一空,那么我們只能靠自己的眼睛一直盯著網(wǎng)站嗎?NoNoNo,作為計(jì)算機(jī)專業(yè)的學(xué)生,怎么能為這種事情浪費(fèi)時(shí)間呢?那肯定想法就是寫爬蟲(chóng)自動(dòng)比對(duì)價(jià)格啊,后來(lái)又在想,爬蟲(chóng)數(shù)據(jù)也是在PC端啊,該怎么實(shí)時(shí)提醒我們呢?再弄一個(gè)微信機(jī)器人發(fā)送數(shù)據(jù)不就可以了嗎?說(shuō)干就干,代碼開(kāi)擼
先看下效果:
準(zhǔn)備工作:
首先本文使用py3,需要安裝以下庫(kù):
1)itchat
2)requests
3)apscheduler
分析網(wǎng)頁(yè):
首先我們需要做什么?毫無(wú)疑問(wèn),分析網(wǎng)頁(yè),因?yàn)樽钪匾囊徊骄褪谦@取數(shù)據(jù),那么如何獲取數(shù)據(jù)就是我們首先要克服的困難
附上 nike nba專區(qū)地址:https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux
首先我們要明確一個(gè)地方,我們的目的是實(shí)時(shí)監(jiān)控?zé)衢T打折球衣,所以我們的價(jià)格肯定首先降序排列,不過(guò)先不用著急,打開(kāi)F12先看下調(diào)試器,對(duì)了我使用的是chrome瀏覽器
由于我們是先打開(kāi)網(wǎng)頁(yè)再打開(kāi)調(diào)試窗口,所以目前我們看不到數(shù)據(jù),別急,我們刷新一下再看
哦吼,完蛋,怎么這么多東西貌似根本沒(méi)法看
別急 繼續(xù)分析,作為一個(gè)學(xué)(qiong)生(bi),我們肯定先關(guān)注價(jià)格了,當(dāng)然要升序排列啊!
好的 點(diǎn)下瀏覽器調(diào)試窗口中的清除按鈕(就是下面這個(gè)藍(lán)色標(biāo)記的按鈕)先清除下調(diào)試臺(tái)中的數(shù)據(jù) 然后呢我們點(diǎn)下篩選方式價(jià)格由低到高(紅色標(biāo)記的菜單鍵中選擇)
得到調(diào)試臺(tái)如下,完蛋了還是一堆怎么辦?
沒(méi)關(guān)系,至少現(xiàn)在網(wǎng)頁(yè)內(nèi)容已經(jīng)是按照價(jià)格升序排列了,我們?cè)賮?lái)看看得到的Network數(shù)據(jù),挨個(gè)點(diǎn)一點(diǎn)看看,發(fā)現(xiàn)當(dāng)點(diǎn)到名稱為graphql開(kāi)頭的文件里去時(shí)候,有東西出現(xiàn)了
里面的響應(yīng)內(nèi)容出現(xiàn)了幾個(gè)熟悉的隊(duì)名稱和球員名稱甚至還有價(jià)格,等等,這不就是我們要的數(shù)據(jù)嗎?
看來(lái)我們找對(duì)了地方,我們雙擊點(diǎn)開(kāi)graphql開(kāi)頭的網(wǎng)頁(yè)文件看看會(huì)有什么呢? 。。。 看起來(lái)雜亂無(wú)章,但是貌似確實(shí)是我們要的數(shù)據(jù),是json格式的
在網(wǎng)頁(yè)上看json簡(jiǎn)直是折磨,好的,我們用python開(kāi)始把這個(gè)網(wǎng)頁(yè)內(nèi)容給弄下來(lái)仔細(xì)研究下
pycharm開(kāi)搞
import requests import json # 剛剛在調(diào)試臺(tái)得到的地址 url= ' https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc ' # 使json數(shù)據(jù)格式化輸出更好觀察 def better_jsprint(json_obj): # 使用indent=4 這個(gè)參數(shù)對(duì)json進(jìn)行數(shù)據(jù)格式化輸出 # 因?yàn)閖son.dumps 序列化時(shí)對(duì)中文默認(rèn)使用的ascii編碼.想輸出真正的中文需要指定ensure_ascii=False return json.dumps(json.loads(json_obj),indent=4,ensure_ascii= False) response = requests.get(url) print (better_jsprint(response.text))
看看輸出什么:
這樣看起來(lái)好多了,好的 似乎到這里我們已經(jīng)可以開(kāi)始選取我們需要的數(shù)據(jù)進(jìn)行記錄了,但是我們又會(huì)注意到一點(diǎn),這個(gè)網(wǎng)頁(yè)的內(nèi)容是瀑布流方式,也就是說(shuō)滾輪往下滾動(dòng)才會(huì)有更多的數(shù)據(jù)出現(xiàn),可是我們目前只獲取了這個(gè)頁(yè)面最上端的數(shù)據(jù),如果我們想獲取更多的數(shù)據(jù)怎么辦?
我們還是使用調(diào)試臺(tái),其實(shí)他頁(yè)面只要變化,網(wǎng)站交互一定是有活動(dòng)的,所以我們現(xiàn)在就觀察當(dāng)滾輪往下滾動(dòng)到瀑布流下端時(shí)調(diào)試臺(tái)會(huì)出現(xiàn)什么東西就可以了
往下滾動(dòng),發(fā)現(xiàn)調(diào)試臺(tái)確實(shí)出現(xiàn)了很多新的文件,我們猜想這些文件中一定有瀑布流下端的數(shù)據(jù),對(duì)了還記得我們剛才找到的文件名是什么嗎?對(duì)的,是名稱為graphql開(kāi)頭的文件,那么會(huì)不會(huì)新的數(shù)據(jù)文件也是這個(gè)名字開(kāi)頭的呢?我們使用調(diào)試臺(tái)搜索下看看
來(lái)了來(lái)了,它真的出現(xiàn)了,現(xiàn)在出現(xiàn)了3個(gè)文件都是graphql名字開(kāi)頭,毫無(wú)疑問(wèn)第一個(gè)文件是我們上面找到的,那么第二個(gè)第三個(gè)呢? 我們點(diǎn)開(kāi)看看,會(huì)發(fā)現(xiàn)對(duì)應(yīng)的商品名稱之類的真的是瀑布流下端的數(shù)據(jù)。
OK看起來(lái)我們現(xiàn)在確實(shí)得到了所有數(shù)據(jù)文件的url
我最初的想法是直接將3個(gè)url寫到一個(gè)列表中然后使用循環(huán)讀取如下圖(其實(shí)會(huì)發(fā)現(xiàn)第二個(gè)url與第三個(gè)看起來(lái)貌似一樣啊怎么回事?下面有解釋別急)
后來(lái)呢我突然意識(shí)到,萬(wàn)一商品更多了怎么辦?會(huì)不會(huì)出現(xiàn)4個(gè)5個(gè)url?而總不能每次都靠人力去數(shù)有多少個(gè)url吧?然后就想,怎樣才能讓程序自動(dòng)添加url呢?
我們?cè)倩仡^看看第一次抓取下來(lái)的 url1 的json數(shù)據(jù),首先嘗試下檢索page這個(gè)關(guān)鍵詞(畢竟一般程序員都會(huì)寫這個(gè)作為頁(yè)面標(biāo)識(shí)吧?),哦霍,發(fā)現(xiàn)了了不得的東西,
這些數(shù)據(jù)看起來(lái)很眼熟啊,還有uuids?再比對(duì)下第一次抓的 url1 發(fā)現(xiàn)里面的uuids還真的就是json里面的數(shù)據(jù),那么又看到pages里面有個(gè)next 納尼?這會(huì)不會(huì)是瀑布流下半部分url組成呢?快來(lái)比對(duì) url2 地址
https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&
endpoint=
%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D24%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc
嘗試檢索下next中的內(nèi)容,發(fā)現(xiàn)真的存在與endpoint參數(shù)后面,哦霍 現(xiàn)在我們猜想,會(huì)不會(huì)每個(gè)json中都包含pages next這個(gè)數(shù)據(jù)
打印url2繼續(xù)檢索pages的next?
真的存在,并且還存在prev參數(shù)(前一頁(yè)),說(shuō)明我們的猜想可能是正確的,這時(shí)候細(xì)心的小伙伴可能發(fā)現(xiàn)了 url2中的next內(nèi)容與url1中一致啊,哦原來(lái)是這樣,這樣才導(dǎo)致了我們剛剛調(diào)試臺(tái)中出現(xiàn)3個(gè)url文件但是第二個(gè)與第三個(gè)一樣的情況
但是我們猜想第三個(gè)url返回?cái)?shù)據(jù)中應(yīng)該沒(méi)有next否則就應(yīng)該出現(xiàn)第四個(gè)文件了,我們來(lái)試一試
在url3返回?cái)?shù)據(jù)中檢索next
真的為空了所以我們可以確定,只要瀑布流下方仍有數(shù)據(jù),那么一定存在next參數(shù) 因此我們可以確定瀑布流url寫法 我們網(wǎng)頁(yè)分析完成 接下來(lái)就要進(jìn)行真正的代碼編寫了
(其實(shí)我有一個(gè)疑問(wèn) url2與url3看起來(lái)確實(shí)是一模一樣的并且我嘗試做了差值運(yùn)算,發(fā)現(xiàn)還是一樣的,但是返回?cái)?shù)據(jù)確實(shí)不同,有大神可以發(fā)現(xiàn)這兩個(gè)url不同之處嗎 下面放上這兩個(gè)url)
(url已改變,根據(jù)官網(wǎng)實(shí)時(shí)更新數(shù)據(jù)一直在變)
url2= ' https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D24%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc ' url3 = ' https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D48%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc '
urls構(gòu)建與objects獲取
我們首先需要寫遞歸函數(shù)獲取所有urls
我們觀察json內(nèi)容就會(huì)發(fā)現(xiàn)我們需要的商品數(shù)據(jù)都在一個(gè)名為objects的key中 因此需要將所有objects放在一起
遞歸函數(shù)(核心函數(shù))如下
# 剛剛在調(diào)試臺(tái)得到的初始地址 url1= ' https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc ' # 觀察其他urls發(fā)現(xiàn)前面參數(shù)是一樣的如下 我們先寫前半部分 urlother= ' https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint= ' urls = [url1] # 空l(shuí)ist存放物品信息 觀察發(fā)現(xiàn)json中的objects數(shù)據(jù)類型為list pricedictlist= [] # 遞歸函數(shù)得到urls列表以及每個(gè)url中物品數(shù)據(jù) def get_url_objcts(url= url1): # 首先得到初始url的json數(shù)據(jù) response= requests.get(url) # 只取有用的數(shù)據(jù)內(nèi)容 仔細(xì)觀察json數(shù)據(jù) 得到下一個(gè)頁(yè)面的next參數(shù) # urllib.parse.quote(text) # 按照標(biāo)準(zhǔn), URL 只允許一部分 ASCII 字符(數(shù)字字母和部分符號(hào)),其他的字符(如漢字)是不符合 URL 標(biāo)準(zhǔn)的。 # 所以 URL 中使用其他字符就需要進(jìn)行 URL 編碼。 try : nextpage_json =quote(response.json()[ ' data ' ][ ' filteredProductsWithContext ' ][ ' pages ' ][ ' next ' ]) # 添加objects內(nèi)容到列表 pricedictlist.extend(response.json()[ ' data ' ][ ' filteredProductsWithContext ' ][ ' objects ' ]) except KeyError: nextpage_json = quote(response.json()[ ' data ' ][ ' products ' ][ ' pages ' ][ ' next ' ]) # 添加objects內(nèi)容到列表 pricedictlist.extend(response.json()[ ' data ' ][ ' products ' ][ ' objects ' ]) except TypeError: nextpage_json = '' # 遞歸獲取url與objects if nextpage_json!= '' : urlnext =urlother+ nextpage_json urls.append(urlnext) nextpage_json = '' get_url_objcts(urlnext) # else只在不存在下一頁(yè)時(shí)執(zhí)行,相當(dāng)于此時(shí)已經(jīng)完成了objects的獲取 下面構(gòu)建發(fā)送信息 else : i = 0 STR = str( ' https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux?sort=priceAsc ' ) compStr1 = '' for each in pricedictlist: title = each[ ' publishedContent ' ][ ' properties ' ][ ' seo ' ] if title == None: continue currentPrice = each[ ' productInfo ' ][0][ ' merchPrice ' ][ ' currentPrice ' ] fullPrice = each[ ' productInfo ' ][0][ ' merchPrice ' ][ ' fullPrice ' ] # 只選取有用的數(shù)據(jù) 我們不要童裝 同時(shí)只要打折商品 if ( not re.search( ' 童 ' , str(title[ ' slug ' ]))) and (fullPrice != currentPrice): i = i + 1 STR = STR + ' \n\n ' + ((str(title[ ' slug ' ]) + " \n " + " 原價(jià) " + str(fullPrice) + " 現(xiàn)價(jià) " + str( currentPrice)) + ' ' + str(currentPrice * 100 / fullPrice) + ' % ' ) # 發(fā)現(xiàn)每個(gè)商品名稱后面都有獨(dú)特的商品碼為6個(gè)字母標(biāo)識(shí),所以切片記錄下來(lái)用于對(duì)比 compStr1 = compStr1 + str(title[ ' slug ' ][-6 :]) STR = STR + ' \n ' + ( " 本次數(shù)據(jù)一共: " + str(i) + " 個(gè) " )
這之上 我們已經(jīng)完成了數(shù)據(jù)的獲取,接下來(lái)就是微信機(jī)器人發(fā)送了
itchat微信機(jī)器人
itchat是個(gè)人賬戶的開(kāi)放源碼wechat api項(xiàng)目, 它使您可以通過(guò)命令行訪問(wèn)您的個(gè)人微信帳戶。
如何向群發(fā)送消息?
import itchat # 登錄微信網(wǎng)頁(yè)版 參數(shù)enableCmdQR=0會(huì)出現(xiàn)圖片二維碼登錄 為1則命令行窗口輸出字符二維碼 有的linux因?yàn)樽址g距問(wèn)題需要設(shè)置為2 itchat.auto_login(hotReload=0,enableCmdQR= 0) # 自己創(chuàng)建微信群,名稱自定,并且要保存到通信錄 chatroomName = ' Money ' # 群名 itchat.get_chatrooms(update= True) chatrooms = itchat.search_chatrooms(name= chatroomName) # print(compStr0) if len(chatrooms) == 0: # print('沒(méi)有找到群聊:' + chatroomName) exit(0) else : itchat.send_msg( ' hello world ' , toUserName=chatrooms[0][ ' UserName ' ]) # 發(fā)送消息
這就是簡(jiǎn)單的發(fā)送消息了,將我們上面的程序接合就可以實(shí)現(xiàn)微信發(fā)送了 還差一步,沒(méi)錯(cuò)就是定時(shí)任務(wù)的問(wèn)題
Python定時(shí)任務(wù)框架apscheduler
聽(tīng)名字就知道是干什么的 沒(méi)錯(cuò)就是任務(wù)調(diào)度,我們可以使用這個(gè)庫(kù)簡(jiǎn)潔的實(shí)現(xiàn)任務(wù)調(diào)度問(wèn)題
簡(jiǎn)單例程如下:
from apscheduler.schedulers.blocking import BlockingScheduler import time scheduler = BlockingScheduler() def job1(): print ( " %s: 執(zhí)行任務(wù) " % time.asctime()) scheduler.add_job(job1, ' interval ' , seconds=3 ) scheduler.start()
輸出:
Mon Aug 19 18:35:52 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:35:55 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:35:58 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:36:01 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:36:04 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:36:07 2019 : 執(zhí)行任務(wù) Mon Aug 19 18:36:10 2019: 執(zhí)行任務(wù)
最后一步就是將上面講的所有來(lái)一個(gè)大集合
程序送上~:
將環(huán)境配置好,直接放在自己的服務(wù)器就可以運(yùn)行了,這一步就不再贅述
import re import requests from urllib.parse import quote import itchat from datetime import datetime from apscheduler.schedulers.blocking import BlockingScheduler # 登錄微信網(wǎng)頁(yè)版 參數(shù)enableCmdQR=0會(huì)出現(xiàn)圖片二維碼登錄 為1則命令行窗口輸出字符二維碼 有的linux因?yàn)樽址g距問(wèn)題需要設(shè)置為2 itchat.auto_login(hotReload=0,enableCmdQR= 2) # 比較字符串,用于判斷是否更新數(shù)據(jù) compStr0= ' fuckkkkkkkkkkkkkkkk ' def main(): # 剛剛在調(diào)試臺(tái)得到的初始地址 url1= ' https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc ' # 觀察其他urls發(fā)現(xiàn)前面參數(shù)是一樣的如下 我們先寫前半部分 urlother= ' https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint= ' urls = [url1] # 空l(shuí)ist存放物品信息 觀察發(fā)現(xiàn)json中的objects數(shù)據(jù)類型為list pricedictlist= [] # 遞歸函數(shù)得到urls列表以及每個(gè)url中物品數(shù)據(jù) def get_url_objcts(url= url1): # 首先得到初始url的json數(shù)據(jù) response= requests.get(url) # 只取有用的數(shù)據(jù)內(nèi)容 仔細(xì)觀察json數(shù)據(jù) 得到下一個(gè)頁(yè)面的next參數(shù) # urllib.parse.quote(text) # 按照標(biāo)準(zhǔn), URL 只允許一部分 ASCII 字符(數(shù)字字母和部分符號(hào)),其他的字符(如漢字)是不符合 URL 標(biāo)準(zhǔn)的。 # 所以 URL 中使用其他字符就需要進(jìn)行 URL 編碼。 try : nextpage_json =quote(response.json()[ ' data ' ][ ' filteredProductsWithContext ' ][ ' pages ' ][ ' next ' ]) pricedictlist.extend(response.json()[ ' data ' ][ ' filteredProductsWithContext ' ][ ' objects ' ]) except KeyError: nextpage_json = quote(response.json()[ ' data ' ][ ' products ' ][ ' pages ' ][ ' next ' ]) pricedictlist.extend(response.json()[ ' data ' ][ ' products ' ][ ' objects ' ]) except TypeError: nextpage_json = '' # 遞歸獲取url與objects if nextpage_json!= '' : urlnext =urlother+ nextpage_json urls.append(urlnext) nextpage_json = '' get_url_objcts(urlnext) # else只在不存在下一頁(yè)時(shí)執(zhí)行,相當(dāng)于此時(shí)已經(jīng)完成了objects的獲取 else : i = 0 STR = str( ' https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux?sort=priceAsc ' ) compStr1 = '' for each in pricedictlist: title = each[ ' publishedContent ' ][ ' properties ' ][ ' seo ' ] if title == None: continue currentPrice = each[ ' productInfo ' ][0][ ' merchPrice ' ][ ' currentPrice ' ] fullPrice = each[ ' productInfo ' ][0][ ' merchPrice ' ][ ' fullPrice ' ] # 只選取有用的數(shù)據(jù) 我們不要童裝 同時(shí)只要打折商品 if ( not re.search( ' 童 ' , str(title[ ' slug ' ]))) and (fullPrice != currentPrice): i = i + 1 STR = STR + ' \n\n ' + ((str(title[ ' slug ' ]) + " \n " + " 原價(jià) " + str(fullPrice) + " 現(xiàn)價(jià) " + str( currentPrice)) + ' ' + str(currentPrice * 100 / fullPrice) + ' % ' ) # 發(fā)現(xiàn)每個(gè)商品名稱后面都有獨(dú)特的商品碼為6個(gè)字母標(biāo)識(shí),所以切片記錄下來(lái)用于對(duì)比 compStr1 = compStr1 + str(title[ ' slug ' ][-6 :]) STR = STR + ' \n ' + ( " 本次數(shù)據(jù)一共: " + str(i) + " 個(gè) " ) # 自己創(chuàng)建微信群,名稱自定 chatroomName = ' Money ' # 群名 itchat.get_chatrooms(update= True) chatrooms = itchat.search_chatrooms(name= chatroomName) global compStr0 # print(compStr0) if len(chatrooms) == 0: # print('沒(méi)有找到群聊:' + chatroomName) exit(0) else : # 判斷數(shù)據(jù)是否變化 if (compStr1 != compStr0): itchat.send_msg(STR, toUserName =chatrooms[0][ ' UserName ' ]) # 發(fā)送消息 compStr0 = compStr1 # print(compStr0) get_url_objcts() sched = BlockingScheduler() # 任務(wù)調(diào)度 每2分鐘觸發(fā) 時(shí)間自定 sched.add_job(main, ' interval ' , minutes=2, next_run_time= datetime.now()) sched.start() itchat.run()
轉(zhuǎn)載請(qǐng)注明出處 thank you!
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
