龙空技术网

不会用Power Query爬取网页?大神亲自详细示范6个案例教会你!

office高效办公 770

前言:

而今看官们对“手机html锚”都比较珍视,大家都想要知道一些“手机html锚”的相关知识。那么小编同时在网摘上收集了一些关于“手机html锚””的相关知识,希望朋友们能喜欢,大家一起来了解一下吧!

原理见《PowerQuery爬取网页终极攻略——Power Query网络爬取详解》。施阳大神的手笔。pqfans是个好去处,有兴趣的可以多瞄瞄。

1、翻页URL会变化,直接get方式提交

URL:

此为沪深A股数据,需要抓取1-20页的所有数据。点击下一页后观察URL发现,html前面最后一个数字即为页数,那么只需要自定义函数,将其做成变量然后调用即可。另外发现每一页的最后一行都是多余的,可以用Table.RemoveLastN删掉。

let get_data =(x)=>Table.RemoveLastN(Web.Page(Web.Contents(""&Text.From(x)&".html")){0}[Data],1), result = Table.Combine(List.Transform({1..20},get_data))in result
2、翻页URL不会变化,F12找出真实地址

URL:

要抓取1-20页数据,但发现翻页URL不会变,无法根据URL控制页数。浏览器按F12发现,网页以get方式提交,图中参数4即为页数,表格的真实URL为,于是方法同上。

let source = Table.Combine(List.Transform({1..20},each Web.Page(Web.Contents(""&Text.From(_))){2}[Data])), result = Table.SelectRows(source, each not Text.StartsWith([药品编码], "当前"))in result
3、post方式提交

URL:;ApprovalDateEnd=2016-12-31

和之前不同的是,该网页是以post方式提交,如果只是在URL后加参数无法得到正确的页数,于是要用到Web.Contents中的Content提交post参数,另外headers中的Content-Type是必须的,所以也要加进来。因为有个"-"为特殊符号,所以要加个#""。

需要注意的是,提交的参数需要是encode后的,__VIEWSTATE参数太长了,我没放进来,自己改一下。

let get_data = (page)=> let url="", headers=[#"Content-Type"="application/x-www-form-urlencoded"], content="__EVENTTARGET=GridViewNational&__EVENTARGUMENT=Page%24"&Text.From(page)&"&__VIEWSTATE=太长了自己改吧", query=[ApprovalDateStart="2016-01-01",ApprovalDateEnd="2016-12-31"], web_data=Web.Contents(url,[Query=query,Headers=headers,Content=Text.ToBinary(content)]), data=Table.RemoveLastN(Web.Page(Text.FromBinary(web_data))[Data]{0},1) in data, result = Table.Combine(List.Transform({1..78},get_data))in result
4、需要登录,加cookies

URL:;action=index&parenttab=Parent%20Accounts

这是一个CRM的试用账户,现要抓出客户分类中的vip客户下的1-4页的所有信息。这里面有三个问题要解决:①需要登陆 ②点击客户分类下的任何子分类URL都不会变,如何定位到我们想要的vip客户 ③翻页问题

我们首先打开这个URL验证下手机号登陆,然后打开一个新窗口,再次打开这个URL,发现看到的已经和刚才不一样了,这是因为刚才登陆后服务器已经把所有的身份识别信息记录在cookies中,当再次访问的时候浏览器检查到本地有cookies,于是向服务器提交了一个headers中带有cookies的请求,验证通过。所以我们只需要复制cookies添加到headers中即可,问题①解决。

然后尝试点击客户分类下的不同子分类,对比发现有一个叫viewname的参数在变化,而vip客户对应的参数为179,问题②解决。

页码对应的则是start参数,上面介绍过,问题③解决。

let  get_data=(page)=> let url="", headers=[#"Content-type"="application/x-www-form-urlencoded",Cookie="ck_login_id_lingdang=201; ck_login_theme_lingdang=softed; ck_login_language_lingdang=zh_cn; IESESSION=alive; _qddamta_4008885110=3-0; pgv_pvi=1109719040; pgv_si=s9133628416; tencentSig=2914921472; Hm_lvt_15823373277d5586cce1d8fa22740e98=1498477295,1498478011; Hm_lpvt_15823373277d5586cce1d8fa22740e98=1498478011; LXB_REFER=; _qddaz=QD.evgckn.ew8amb.j4e2ox3t; PHPSESSID=j0m2ou15d8hcumonfcul46kj64; _qdda=3-1.3bt43b; _qddab=3-i0t2ae.j4e2ox3v"], content="viewname=179&start="&Text.From(page), query=[action="index",module="Accounts"], web_data=Web.Contents(url,[Query=query,Headers=headers,Content=Text.ToBinary(content)]), table=Web.Page(Text.FromBinary(web_data)){0}[Data] in table, result=Table.RemoveColumns(Table.Combine(List.Transform({1..4},get_data)),{""})in result
5、返回json:

URL:

要抓取2011-2016所有欧冠积分榜数据。通过F12不难找到真实地址,去掉无关参数后为;_sport_s_=opta&_sport_a_=teamOrder&app_key=3571367214&type=10&season=2016。把这个地址复制到浏览器打开,发现出来的和上面的案例都不一样,返回的是json,那么就需要使用Json.Document来解析,其中season参数控制赛季,自定义函数后构建{2011..2016}的list调用即可:

let get_data=(x)=>Table.FromRecords(Json.Document(Web.Contents(";_sport_s_=opta&_sport_a_=teamOrder&app_key=3571367214&type=10&season="&Text.From(x)))[result][data]), result = Table.Combine(List.Transform({2011..2016},get_data))in result
6、非结构化数据:

以上案例都有一个共同点:都为结构化数据,可以直接通过解析表或json等方式从而获取数据,但有些网页中的数据是非结构化的。

例如:爬取本站页面中所有的锚链接。

对于这种非结构化的网页,只能通过Text.FromBinary解析出源码,然后当文本处理。如果网页的编码为GBK或GB2312,Text.FromBinary的第二参数要加个0,否则会出现乱码,如果是UTF-8则不用第二参数。

let source = Text.FromBinary(Web.Contents("")), result = List.Transform({0..List.Count(Text.PositionOf(源,"<a href=""",2))-1},each ""&Text.BetweenDelimiters(源,"<a href=""","""",_))in result
处理动态参数

对于动态参数,可以把变量写在单元格中,然后将单元格导入PQ,效果如下图:

修改单元格中的值,刷新即可得到不同日期、不同类型等数据,体验类似于网页中的查询。

练习

URL:

请用以上介绍的方法,抓出2017/6/20-2017/6/23全部49页的全国城市空气质量日报。

来源于施阳大神。

标签: #手机html锚