整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          php利用curl方法和正則表達式提取網頁內容

          php利用curl方法和正則表達式提取網頁內容

          者:phill

          在web開發中,有時需要從其他網頁的內容中提取我們需要的信息,抓取頁面信息需要使用curl方法,但是要從所抓取到的信息中提取到我們真正需要的內容,需要使用正則表達式進行匹配。

          這里,我將簡單闡述如何利用正則匹配,從網站的頁面中提取我們想要的招聘信息,具體分為以下幾步:

          1、分析我們要抓取內容網頁的url構成;

          2、根據實際情況拼接我們需要的url;

          3、讀取網頁內容;

          4、根據返回的內容使用正則匹配出我們需要的內容;

          步驟一 分析url構成:

          在網站的搜索職位頁面中,選定工作地點和職位后進行搜索,

          發現其url構成如下:

          http://xxx.xxx.com/jobs/searchresult.asp?jl=%E7%BB%B5%E9%98%B3&kw=java&sm=0&p=1

          其中:

          ? ji參數的值為工作地點:這里看到的值”%E7%BB%B5%E9%98%B3”并非亂碼;而是對中文使用urlencode后的結果,我們也可以直接跟明碼,比如ji=綿陽;

          ? Kw參數的值為職位;

          ? p參數為頁碼;

          步驟二 現在我們構建想要訪問的url:

          步驟三 使用file_get_contents函數抓取該網站內容:

          現在需要使用Google瀏覽器的調試工具,觀察一下此部分的html結構,以便編寫對應的正則表達式:

          該部分內容的html結構均為:

          步驟四 使用正則表達式匹配出需要的內容:

          先使用正則表達式匹配出該部分的值,參照以上html結構,所構建的正則表達式(這里我們使用效率更高的PCRE模式)為:

          我們使用匹配函數preg_match_all:

          通過以上匹配,可以將匹配到的內容放入$arr這個數組中,返回內容如下:

          繼續使用正則表達式匹配到我們需要的內容,但是之前構建的url中頁碼值為1,我們需要匹配到所有的頁,所以需要修改之前的url,并且我們需要使用循環,但是要用到何種循環結構呢?我們需要先觀察頁面中“下一頁”按鈕的html結構:

          我們可以匹配上圖中a標簽中的class名稱“nopress2”判斷是否還有下一頁,如果能匹配出該值,說明沒有下一頁,所以我們使用do……while循環結構來獲取所有的頁面內容,代碼修改如下:

          當匹配到“nopress2”時,while條件不再滿足,停止循環。

          1、根據以下html結構,找到職位名稱和對應的a標簽中的url

          這里使用foreach遍歷我們剛才得到的數組$arr,將代碼添加至do……while內:

          2 找到公司名稱和對應的url,在foreach中繼續添加代碼

          3 匹配出配置職位月薪、工作地點、發布時間,繼續添加代碼

          經過以上處理,最終將得到一個如下形式的數組:

          至此,我們已經得到了想要提取的數據。

          完整代碼:

          該文章只是提供了一種在網頁上爬取我們想要的內容的大致方法,中間有些步驟和代碼還可以繼續優化,還存在不足之處,歡迎大家一起討論,畢竟在編程中,沒有最好的代碼,只有更好的思想。

          hp修改html標簽中的內容php與html如何配合使用php改變htmlphp過濾htmlphp輸出html標簽

          PHP刪除HTMl標簽的三種解決方法_流年-CSDN博客_php去除htm...

          2017年9月19日 在PHP中可以使用strip_tags函數去除HTML標簽,看下面示例: 復制代碼代碼如下: <?php $str=‘www<p>dreamdu</p>.com'; echo(htmlspecialchars($str).”<br>”);...

          CSDN技術社區

          百度快照

          php去除HTML標簽實例_php實例_腳本之家

          2013年11月6日 在php中要去除字符串中的HTML標簽方法有很多種,最常用的就是使用strip_tags函數一并去了,只保留字符了,還在就是有選擇性的去除了這里要用正則表達式了,下面寫二...

          ower Query并不是一個專門的網抓或者爬蟲工具,沒有編程語言那么專業,實現的功能也比較有限,但其優勢就是簡單易學,且無縫對接excel,所見即所得。

          本文將以純新手的角度,介紹一些基礎的網抓知識,盡可能讓每個人都能學會。

          網抓主要分為三個步驟:

          1、抓包并分析請求

          2、構建并發送請求

          3、對返回的數據清洗。

          背景知識:靜態網頁和動態網頁

          靜態網頁

          首先來看一個最簡單的案例:

          http://quote.stockstar.com/stock/ranklist_a_3_1_1.html
          

          這是一個靜態頁面,以html結尾,當你點擊不同欄目不同頁碼的時候,URL也在相應的發生變化。

          對服務器來說,靜態頁面是實實在在保存在服務器上的文件,每個網頁都是一個獨立的文件。所以比如我們要抓某一頁的數據,只需要點擊新建查詢-從其他源-自網站,把對應的URL輸入進去就可以了,這和我們導入本地xlsx文件的原理是一樣的,至于如何批量抓取多頁我們下面再講。

          但是靜態頁面缺點很明顯:沒有數據庫支持,交互性差,非常不便于維護,所以大多數網站會采用動態頁面設計,這就導致了我們想要抓取數據變得沒那么簡單。

          動態網頁

          什么是動態頁面?打個比方,打開百度首頁,搜索關鍵詞powerquery。

          URL去掉無關參數精簡后為:

          https://www.baidu.com/s?wd=powerquery
          

          搜索不同關鍵詞只是wd=后面的部分在變化。

          試想網民搜索關鍵詞的可能性有無窮多,百度會為每一種可能做一個文件放在服務器里么?顯然不會。

          我們之所以能夠看到不同的結果是因為當我們搜索關鍵詞時,會使用GET方式向服務器提交帶參數的請求,比如上面?后面的就是參數,wd是字段名,powerquery是值。當服務器接收到參數后,計算并返回給我們相應的結果。

          那GET又是什么?這就要從HTTP協議開始說起了。

          我們之所以能夠使用瀏覽器訪問網頁,實際上就是瀏覽器向服務器提交請求(request),服務器收到請求后返回了響應(response)并把HTML代碼發送給瀏覽器,瀏覽器解析并顯示出來。

          如上所說,對于動態頁面我們請求的訪問地址始終是同一個https://www.baidu.com/s,如果要讓服務器知道我們想看什么,就需要一種東西來在客戶端與服務器端之間進行消息傳遞,這就是HTTP協議請求。

          HTTP協議請求主要有GET,POST,PUT,DELETE等等,分別對應查、改、增、刪四個操作,其中最常見的就是GET和POST。GET僅請求資源,POST會附帶一個Body包含用戶數據。

          GET請求的數據會附在URL之后,以?分割URL和傳輸數據,參數之間以&相連。上面百度的案例就是GET,再長點的話比如這樣:

          https://www.baidu.com/s?wd=power%20query%E7%BD%91%E6%8A%93&pn=10
          

          這里有wd和pn兩個參數,以&相連,中間的亂碼是中文經過URL encoded轉碼后的結果,如果再有其他參數則繼續在后面追加&即可。

          POST對應改,請求提交的數據放置在HTTP包的Body中。比如你在下方發表評論,你并不能通過URL看出來你究竟向我提交了什么,而當你評論完,頁面上出現了你的評論,我的網站已經被你修改了,這就是在提交POST請求。當然POST也可以用來查詢數據,是一種更加安全的傳遞方式。

          看到這里,我們已經知道了客戶端和服務器端是如何進行信息傳輸的:客戶端提交request,服務器返回response。注意我們這里說的是客戶端,瀏覽器算一種,當然還有其他很多種,比如我們今天要講的Power Query。

          那么網抓的原理其實就是,找出我們所需要抓的數據,分析是瀏覽器向服務器提交了什么請求哪些參數,然后用Power Query構建同樣的請求發送給服務器,服務器便會把對應的數據在Power Query中返回給我們。

          了解了這個,下面我們就開始進行第一步:抓包。

          抓包

          網抓的關鍵在于抓包,一旦抓到包后面都好做。而在抓包的時候,一定要靈活變通,比如在抓一些電商網站數據時,PC端往往比較難抓,所以可以考慮PC轉移動,去抓移動端網站,在Chrome中的F12窗口左上角可以一鍵切換PC和移動模式。再比如抓QQ好友列表,你直接抓軟件是抓不到的,那你就思考除了在軟件還可能在哪里有接口?比如QQ空間里@好友的時候,給好友充值QB的時候,都可以輕松獲取到好友列表。一旦想通這點,你會發現網抓原來這么簡單。抓包可以用瀏覽器自帶的調試工具,按F12即可調出,比較輕量,但缺點是不能支持一些復雜的抓包,但話說回來Power Query本身就不太支持復雜的網抓,所以基本也夠用了。

          建議使用Chrome瀏覽器,下面的案例全部是基于Chrome,所以不要問我其他瀏覽器怎么找。

          http://221.215.38.136/grcx/kscx/list.action?kscxVo.jsp=ylypmlcx.jsp
          

          為例,我們點擊下方無論選多少頁發現URL都不會變化,那么如何獲取到比如第5頁的數據呢?按下F12調出調試工具。如果不起作用的話就右擊選擇檢查-然后點擊Network。

          先簡單介紹一下控制臺。最上面圈出來的那一排,最常見的Elements顯示網頁的結構,Network顯示瀏覽器和服務器的通信。

          我們選擇Network后應該是空的,因為才剛剛呼出控制臺監控通信,而之前的行為是沒有監控的,下方文字提示"通信記錄已激活,請執行request或按F5"。

          下面要做的就是讓瀏覽器發送請求,比如你要抓第5頁你就點擊第5頁或者下一頁,你要抓其他欄目你就點擊對應的欄目,總之目的就是產生查詢數據的行為,讓瀏覽器監測到。

          如果你的點擊讓頁面產生了變化,那么就會出現一條條記錄,每條記錄都是一次請求,瀏覽器會對這些請求按照類型進行分類,如圖中框出來的部分所示,我們要做的就是在產生的這么多條請求中找出是哪條請求讓服務器返回了我們所要的數據。

          其中All是所有類型,數據不可能在CSS,Font之類的里面,按照我的經驗可能性DOC>XHR>JS>其他,當記錄過多產生干擾時可以點擊左上角圈出來的Clear清空重新查找。

          下面請動動你們的小手和我一起做如下幾個操作:1、打開上面的URL,2、按下F12調出Network窗口,3、拉到頁面最下方點擊第5頁。

          按照剛才說的優先級依次找一下:Doc有一條,XHR空的,JS空的,如圖所示。

          在Headers標簽下分為了幾個模塊:

          General中的Requset URL表示請求的訪問地址,Request Method表示請求所使用的方法為GET,所以我們可以通過這里判斷是GET還是POST。

          Response Headers是服務器返回的響應頭,因為我們目前主要是想構建請求所以這部分內容不重要。

          Request Headers是請求頭,其中Cookie經常會用到,Referer有可能會用到,User-Agent是讓服務器識別客戶的設備信息的參數,在其他語言的復雜網抓下有可能用到,但在PQ中基本用不到,這個后面再說。順便說一下,當你訪問一個網站的時候,你電腦什么系統、用的什么瀏覽器、顯示器多大、分辨率多少、瀏覽軌跡這些信息已經全部暴露給對方了,想想是不是感覺很恐怖。

          Query String Parameters是查詢參數,因為是GET方法,所以這些參數已經全部在最上面的Requset URL的?后面了。

          這里所看到的信息是已經經過解析的,在每個模塊的右邊還有一兩個小按鈕,view source表示查詢源代碼,view URL encoded表示查詢轉碼后的。

          講了這么多,那么我們如何確定目前所看到的這條記錄是不是就是能夠返回我們想要數據的請求呢?

          首先我們回想下我們是如何找到這條記錄的,是因為點擊了第5頁。

          所以我們大致能夠推斷出應該是提交了一個字段名和page相關且值=5的參數,而看一下最下方的Query String Parameters或者最上方的Requset URL,其中有個page_ylypmlcxQuery=5,假如我們再點擊第6頁第7頁,這個參數也會對應的變成6,7,所以基本能夠確定就是它了。

          又因為是GET,參數已經全部在URL里了,所以我們可以直接把Requset URL復制粘貼到瀏覽器看一下。

          我們在瀏覽器地址欄里把5改成6,7,8,看到數據也會跟著發生變化。這里除了5還有另一個參數,也不知道是什么玩意,有強迫癥的可以去掉試試,變成

          http://221.215.38.136/grcx/pages/kscx/ylypmlcx.jsp?page_ylypmlcxQuery=5
          

          發現對結果沒影響,那么要抓第5頁的數據我們只需要把這個地址復制到PQ中就可以了。

          繼續下一個案例:

          http://www.drugfuture.com/cndrug/national.aspx?ApprovalDateStart=2016-01-01&ApprovalDateEnd=2016-12-31
          

          同樣要求抓第5頁。

          F12,點擊第5頁,在Doc里發現一條記錄如下圖:

          我們發現Request Method是POST,并且在URL中已經找不到控制頁數的參數了,因為POST提交的參數在Body中。

          在Request Headers中比之前多了一個Content-Type,這個參數用來描述Body的內容類型,所以一般POST類型都需要加上這個參數,否則服務器無法識別提交的Body內容。注意response里也有個Content-Type,不要填錯了。

          在最下方相比GET多了一個Form Data的模塊,其中包含__EVENTTARGET,__EVENTARGUMENT,__VIEWSTATE,__VIEWSTATEGENERATOR四個參數,這里就是我們上面一直所說的POST提交的Body內容。我們很容易發現__EVENTARGUMENT的值為Page就是控制頁數的,繼續點擊第6頁發現參數變成了Page,也就驗證了我們的猜想。

          所以同上一個案例相比,我們只需要把GET換成POST,提交上面的4個參數,再加一個Content-Type表明類型,即可抓到指定的數據。

          以上介紹了使用瀏覽器自帶調試工具分別實現GET和POST抓包的方法,但是畢竟案例比較簡單,基本上都只有一條記錄我們一下子就能找到。但是如果出現的記錄很多,我們可以使用Fiddler來快速定位。

          Fiddler是一款系統代理服務器軟件,下載地址請自行百度。原本是客戶端發送request,服務器返回response,而有了代理之后就相當于在客戶端和服務器之間夾了個小三,客戶端發送request給Fiddler,Fiddler再轉發給服務器,反之亦如此。由于所有的網絡數據都會經過Fiddler,自然Fiddler能夠截獲這些數據,實現網絡數據的抓包。

          安裝好Fiddler后首先進行初始設置。

          Rules,勾選"Remove all Encodings","Hide Image Requests","Hide CONNECTs",然后Tools-Options-HTTPS全部勾上。

          還以上面POST那個案例為例,在瀏覽器中點擊第5頁,在Fiddler中按ctrl+F調出查找窗口,然后在想要抓取的頁面中隨便找一個比較有特征的數據,比如第5頁中有一個產品名稱叫做"維血康顆粒"。又因為我們要找的是服務器返回的response中的數據,所以我們可以選擇Responses Only以縮小查找范圍。

          這樣我們需要的數據所在的請求就會被高亮標記出來。Fiddler界面有很多標簽,我們選擇"Inspectors",此時界面分為三部分,左邊為session框,右上是request框,右下是response框。

          所以在Fiddler中我們要做的就是,ctrl+F查找,然后查看response框確認數據是否在范圍內,然后在request框里找出請求參數。

          request框和response框都提供了多種視圖供我們查看,最好是都選擇Raw,也就是原始數據。這里只是舉了個例子,在實際應用中我們搜索的時候最好搜英文或數字,而不要搜中文,因為可能因為轉碼的問題導致搜不到。

          剛才說到所有的網絡數據都會經過Fiddler,所以使用Fiddler不僅可以抓到瀏覽器中的數據,甚至可以抓到一些應用軟件中的數據,比如說抓QQ群成員。

          打開QQ群資料-成員,剛打開的時候會看到短暫的"正在加載數據,請稍候"的提示。當加載完成后,Fiddler中多了幾條記錄,嘗試搜索"施陽",高亮定位到其中的一條記錄,查看response發現,沒錯這正是我們要的數據。

          一般點擊出現"正在加載"的數據多是如此,大家都可以動手找一下QQ群文件。

          不知不覺已經5000字下去了,但到現在似乎都和Power Query沒多大關系。

          抓包是網抓的第一步也是最重要的一步,這步沒做好或者找錯了那么后面都是徒勞。不管你是使用PQ,還是VBA,還是python,到這一步的方法都是一樣的。

          至此我們已經知道了瀏覽器之所以能夠獲取到數據是因為它到底做了什么,那么下面就開始進入下一步,把剛才瀏覽器做的事交給Power Query去做。

          構建請求

          在M語言中,實現網抓的核心函數是Web.Contents,它能夠對指定的URL向服務器發出request并接受返回的response,先看下函數介紹。

          Web.Contents(url as text, optional options as nullable record) as binary
          

          第一參數就是文本形式的URL,第二參數是可省略的record,包含上圖中那一大坨參數,其中有3個比較常見,其他比較少見就不講了。

          Query:也就是F12中的Query String Parameters,之前也講過這部分的參數也可以加在URL的?后面,以&相連,比如

          =Web.Contents("http://www.baidu.com/s?wd=powerquery")
          

          =Web.Contents("http://www.baidu.com/s", [Query=[wd="powerquery"]])
          

          兩者是等價的,但是后者結構更清晰更便于修改和維護,所以在簡單的情況下使用前者更方便,在參數比較多的復雜情況下更推薦后者。

          Content:如果是GET則不填,一旦填寫此參數將改為POST。填寫內容就是F12里的Form Data,然后點擊view source所看到的一整串文本,同樣參數與參數之間是以&連接的。在Fiddler中就是request框中Raw下的最底部的部分。

          Headers:也就是F12中看到的Request Headers,其中當請求方式為Post時需要Content-Type,需要登錄時要Cookie,部分防盜鏈網站需要Referer。

          服務器返回的數據可能有很多種類型,這個我們先不管,這一步我們的目的就是構建帶參數的request,獲取目標數據的response,我們先全部統一獲取源碼,到下一步再講如何轉換。

          Text.FromBinary能夠將Web.Contents返回的binary解析出HTML源碼,而不同網站的編碼方式不同,中文網站常見的有GBK和UTF-8兩種編碼方式,一般在網頁頭部的meta部分都有聲明。

          所以如果網頁采用GBK編碼,就要給Text.FromBinary加上第二參數0,否則會亂碼,下面有案例會講到。

          講完這個,剩下的就是填空題了。

          GET:

          let
           url="", //Requset URL中?前面的部分
           headers=[Cookie=""], //如果不需要登錄請刪除整行,同時刪除下一行中的Headers=headers
           query=[], //Query String Parameters,即Requset URL中?后面的部分
           web=Text.FromBinary(Web.Contents(url,[Headers=headers,Query=query]))
          in
           web
          

          POST:

          let
           url="",
           headers=[#"Content-Type"="",Cookie=""], //Content-Type必填,如不需要登錄Cookie可省略
           query=[],
           content="",
           web=Text.FromBinary(Web.Contents(url,[Headers=headers,Query=query,Content=Text.ToBinary(content)]))
          in
           web
          

          其中的""和[]就是需要你自己去填的,建議在編輯器軟件中編輯好再粘貼到Power Query的高級編輯器中,在此推薦一款好用的編輯器——Sublime Text,輕量方便顏值高。

          下面結合案例來做填空題:抓QQ郵箱收件箱。

          F12,點擊收件箱-下一頁,在Doc里出現一條mail_list,觀察發現是GET方式,所以用第一個模板。

          又因為郵箱肯定是需要登錄才能訪問的,所以要加上cookie。

          把代碼編輯好復制到高級編輯器,發現返回的源碼有亂碼,再看一眼編碼方式是GBK,所以加上第二參數0,結果正確,你收件箱里某一頁的數據就都出來了。

          很簡單吧,你可以再嘗試抓QQ空間,百度網盤這些,方法都一樣。

          再來舉個特殊情況的案例:http://bond.sse.com.cn/bridge/information/。

          F12,點擊下一頁,這回是在JS里有個commonQuery.do,也不難找到,是GET方式,但是把Request URL復制粘貼到瀏覽器地址欄卻發現打不開,用Power Query也無法抓到數據。

          簡單來說就是網站做了防盜鏈處理,需要加上Request Headers里的Referer。

          當然特殊情況也不止這一種,如果你很確定數據就在這條請求里,但是就是出不來,思考下什么原因?因為F12中本來有很多參數,我們只填了幾個必填的參數,其他都省略了,出不來數據說明我們把某個必要的參數給省略了,那么可以把F12中看到的所有參數全部填上去試下,多半都能返回正確結果。

          另外目前許多網站都部署了SSL認證的HTTPS協議,相當于HTTP的加強版,更加安全,比如本文一開始講到的百度的案例。

          但是Power Query目前對HTTPS支持不是太友好,所以如果碰到URL是https開頭的請改成http,否則很可能會出錯。

          一般來說默認提交的GET或POST參數有很多,但很多都是無效或者不相關的參數,去掉也不影響結果,所以像我這種有強迫癥的就習慣挨個把參數去掉測試。

          本節介紹了如何在Power Query中構建參數并向服務器發出請求,這是最簡單的一步,其實就是填空題套模板。

          這步完成后,可以大致瀏覽下返回的源碼,看下我們要的數據是否在其中,如果沒問題就進行下一步——數據清洗。

          數據清洗

          經過上兩步,我們已經抓到所需要的數據,但是格式比較亂,我們需要對其清洗成為規范的表格。

          服務器返回的數據,有可能是HTML,JSON,XML等格式,舉幾個例子,請分別復制到瀏覽器打開比較下區別:

          HTML:

          http://datacenter.mep.gov.cn:8099/ths-report/report!list.action?xmlname=1462261004631
          

          普通的網頁結構,最簡單的一種情況,HTML源碼中包含table標簽,使用Web.Page能夠直接解析成表格,再深化出table即可。

          JSON:

          http://platform.sina.com.cn/sports_all/client_api?_sport_t_=football&_sport_s_=opta&_sport_a_=teamOrder&app_key=3571367214&type=10&season=2016
          

          純文本形式的結構化數據,一個字段對應一個值,使用Json.Document解析。但解析出來的不是表格而是record,除了我們要的數據還可能包含狀態碼、頁數等等,所以需要找到數據所在的list,使用Table.FromReocrds還原成表。不會也沒關系,到這一步剩下的基本靠純界面操作就能完成。

          XML:

          http://www.cffex.com.cn/sj/hqsj/rtj/201710/18/index.xml
          

          與JSON類似,都是純文本形式的結構化數據,但沒有JSON常見,使用Xml.Tables解析。

          以上都屬于結構化數據,就是能夠通過函數直接或間接轉換為表格,但很多時候我們遇到的可能是一些非結構化數據,比如要抓本站所有文章的標題,它既不是表格,也不是JSON,函數解析不出來,那要怎么搞呢?

          常見的有正則,XPath,CSS Selector等方法,但很遺憾PQ一個都不支持。。。所以PQ在處理這些數據的時候就比較痛苦了,只能保持第二步中Text.FromBinary解析出來的源碼,然后當作文本來用Text類函數提取。

          Web.Contents返回的數據類型為binary,Text.FromBinary把binary解析為text,我們可以直接使用上面三個函數來替換Text.FromBinary的位置解析binary,也可以套在Text.FromBinary的外面來解析text,理論上效果是一樣的,但是有些時候卻直接解析不出來,必須加一個Text.FromBinary,比如案例篇的練習題。

          接下來講很多人關心的翻頁問題,如何批量抓取多個網頁然后合并呢?

          以第一個靜態頁的案例為例

          http://quote.stockstar.com/stock/ranklist_a_3_1_1.html
          

          我們先寫出完整的代碼:

          let
           源=Web.Page(Web.Contents("http://quote.stockstar.com/stock/ranklist_a_3_1_1.html")){0}[Data]
          in
           源
          

          URL結尾的a_3_1_1中最后一個1表示頁數,往后翻會依次變成23456..現在要抓1到10頁,那么我們只要把最后一個數改成23456..依次抓一遍即可。

          但問題是抓不同頁數的代碼只是改了一個數字,其他部分都是一樣的,我們不可能要抓10頁就把代碼重復10遍,這太麻煩了,所以可以把變化的部分做成變量封裝為自定義函數,寫成

          fx=(page)=> Web.Page(Web.Contents("http://quote.stockstar.com/stock/ranklist_a_3_1_1"&Text.From(page)&".html")){0}[Data]
          

          然后用List.Transform遍歷循環{1..10},分別調用自定義函數fx得到一個包含10張表的列表,最后用Table.Combine將10張表合并為一張表,寫成:

          let
           fx=(page)=> Web.Page(Web.Contents("http://quote.stockstar.com/stock/ranklist_a_3_1_1"&Text.From(page)&".html")){0}[Data],
           結果=Table.Combine(List.Transform({1..10},fx))
          in
           結果
          

          注意,頁數是數字,與URL的文本相連時要用Text.From進行數據類型轉換。

          同理,如果要批量抓取多日期、多ID之類的,只要更改自定義函數中的變量即可。

          而如果我們不是要抓前10頁而是所有頁,而且事先是不知道一共有多少頁的怎么辦?如果返回的是JSON,大部分情況下數據中都會包含一個叫做totalpage的字段,所以可以分兩步,第一步先隨便提交一個頁碼拿到totalpage,可參考案例篇附件。

          但是比如你現在正在使用我介紹的方法批量抓取我的網站數據,如果再多幾個你這樣的,那我的網站基本上就炸了。

          一直如此高頻率地訪問網站,那得給服務器帶來多大的壓力。

          所以很多網站會采取防爬蟲措施,如果訪問太頻繁就會被封IP。PQ雖然不支持代理IP池之類的,但是延時還是支持的。

          如果你要抓的網站會封IP,那么可以在自定義函數外面嵌套Function.InvokeAfter,設置每爬一次停頓個5秒。

          比如

          =Function.InvokeAfter(()=>1+1,#duration(0,0,0,5))
          

          你會發現你的電腦算1+1還沒你算的快。

          進階:動態交互

          很多時候我們希望能夠實現類似網頁中的體驗,輸入指定條件比如開始和結束日期,根據指定條件抓取數據,如下圖:

          那么也很簡單,只需要把需要查詢的內容導入PQ,替換自定義函數中的變量即可,可參考案例篇附件。

          另外值得一提的是,上面介紹過抓取需要登錄的網站要加cookie,而cookie是有生命周期的,有時候你發現昨天抓到的數據今天就報錯了,就是因為cookie過期了,你可以打開高級編輯器修改cookie的代碼,但是顯然太麻煩了。所以也可以把cookie寫在單元格中,然后導入PQ,這樣就可以實現在不打開PQ的情況下實現本需要修改代碼的刷新。

          調用API:

          API即應用程序編程接口,調用API能夠實現很多Power Query本身無法實現的功能,比如根據地址獲取經緯度、翻譯、分詞、正則、機器人自動回復等等功能,可參考《使用PQ調用API》。

          調用API的原理和網抓是一樣的,其實很多網站的數據本身也是使用API調出來的。

          一般開發文檔都有詳細說明,是使用GET還是POST,然后根據說明向服務器提交參數即可,返回的數據一般都是JSON。

          部分API有免費限額,就是可以免費調用多少次,超出限額的需要收費,所以常見的比如地圖、翻譯等API都需要去開放平臺注冊為開發者,然后把自己的密鑰加入到提交的參數中。

          編程語言接口:

          上面簡單介紹了一下API,你可以把API理解成封裝在服務器中的自定義函數,只需要向服務器提交函數所需要的參數,就能夠返回你想要的結果。

          那么服務器中的函數是怎么來的?那肯定是用編程語言來寫的,比如PHP,Python等等,流程就是:你通過API提交參數,服務器中的編程語言寫的程序來計算,得出結果并返回給你。

          所以理論上只要是能夠配置服務器環境的編程語言,都可以與PQ形成交互,比如《在Power Query中使用正則表達式》就是用PHP寫的。

          再比如使用Python的bottle包搭建本地服務器框架,便能夠通過訪問localhost與Python交互,可參考《M與Python交互》。

          結語

          此篇長文是施陽大神的手筆,來自于pqfans。本來我想寫一篇:

          但折騰來折騰去發現還是沒法超越施陽這篇文章,于是發來頭條分享。僅作了細微文字上的梳理。擴展鏈接給出了原文鏈接。


          主站蜘蛛池模板: 白丝爆浆18禁一区二区三区 | 国产精品主播一区二区| 久久精品国内一区二区三区| 国产一区二区三区精品久久呦| 国精品无码一区二区三区在线蜜臀| 国产精品特级毛片一区二区三区 | 中文字幕一区二区三区免费视频 | 亚洲成AV人片一区二区密柚| 午夜AV内射一区二区三区红桃视| 国产福利电影一区二区三区,免费久久久久久久精| 国产精品视频无圣光一区| 自慰无码一区二区三区| 国产一区中文字幕| 无码播放一区二区三区| 高清一区二区三区免费视频| 中文字幕一区日韩在线视频| 国产激情一区二区三区 | 亚洲国产精品无码第一区二区三区| 中文字幕无码一区二区免费| 国产一区二区三区免费视频| 欧美日韩综合一区二区三区| 亚洲午夜一区二区电影院| 人妻AV中文字幕一区二区三区 | 亚洲一区二区三区自拍公司| 欲色aV无码一区二区人妻 | 韩国资源视频一区二区三区| 日本在线电影一区二区三区| 午夜精品一区二区三区在线视 | 久久国产精品最新一区| 无码AV中文一区二区三区| 亚洲一区二区三区精品视频| 国产精品成人免费一区二区| 大伊香蕉精品一区视频在线| 国产精品一区二区三区99| 波多野结衣一区二区三区aV高清 | 亚洲一区二区三区免费| 久久无码精品一区二区三区| 中文字幕亚洲一区二区三区| 免费精品一区二区三区第35| 怡红院美国分院一区二区 | 久久中文字幕一区二区|