2023年6月29日发(作者:)
python爬⾍html解析器_数据分析师的编程之旅——Python爬⾍篇(2)HTML解析器作者:李禹锋,重庆芝诺⼤数据分析有限公司数据挖掘⼯程师。呈上⼀篇中发送请求与获取⽹页源码,本⽂着重介绍⽹页源码的解析。主要介绍四种解析⽅式:正则表达式、CSS选择器、XPATH选择器、模块化选择器。我个⼈更倾向于XPATH选择器进⾏解析,所以也着重讲解xpath(选择器会⼀种即可,待深⼊时才会考虑每种选择器的优劣)。⼤部分初识爬⾍的教程中以正则表达式来解析,也有使⽤的模块化选择器(python中主要是BeautifulSoup)⾸先提问,⽹页源码在获取到之后,在python中是什么?——字符串,⼀段很长很长的字符串,之前也提到过,正则表达式就是⼀种⾼级的字符处理⽅法,任何字符问题均可使⽤正则表达式,甚⾄有些特殊的爬⾍需求使⽤正则表达式来解析更为简单,⽽且不⽌是正则,使⽤原⽣的字符处理函数也可以进⾏解析,只是既然有汽车,为什么还要⾛路,除⾮为了锻炼⾃⼰字符处理函数的能⼒。同样,⽹页源码虽然在获取到之后是⼀个字符串,但其本⾝也是有结构的。这个结构在前端设计篇中也略微讲到过。⾸先是由标签对包起来,这就是地基,往上是和两组标签对,⽹页信息包含在head标签内,⽹页内容包含在body标签中,接着⼜是各式的层级结构。如果仅仅是将⽹页源码当成⼀个字符串来处理,不免有点⾃找⿇烦,就像明明可以使⽤因式分解却依旧固执的使⽤求更公式⼀样。介绍的⽅法中后三种均是结构化解析器,也叫做选择器。先介绍xpath选择器,⽐较推荐使⽤。01xpathXpath不是⼀种独⽴的语⾔,⽽是⼀种标识路径的⽅法,是基于XML树状结构的路径查询语⾔。形似⽂件系统的路径写法,有着绝对路径和相对路径。⾸先介绍容易理解⼀些的绝对路径。例如我现在有如下HTML源码。HTML解析⽰例list1的第⼀个listlist1的第⼆个listlist2的第⼀个listlist2的第⼆个list百度链接展现如下两个div的id分别为list1和list2,每个div中的第⼀个li标签class⼀样,第⼆个li标签class⼀样。使⽤绝对路径来定位到每个li标签的⽅法如下:元素xpathDiv1 li1/html/body/div[1]/li[1]Div1 li2/html/body/div[1]/li[2]Div2 li1/html/body/div[2]/li[1]Div2 li2/html/body/div[2]/li[2]绝对路径起始就是从html标签开始,每⼀层标签挨着往下⾛,若同⼀级出现了多个同类标签,使⽤中括号加数字的⽅式来选取第⼏个,注意:xpath是从1开始,不是从0开始。⽽相对路径的学问就⽐较多了,本⽂只介绍⼏个最简单的相对路径写法(基本也够⽤了)。通⽤些的相对路径(从可以定位到唯⼀性的结点开始往后算,⽅法为在中括号中以@开头,然后跟上对应的属性与属性值)元素xpathDiv1 li1//div[@id=”list1”]/li[1]Div1 li2//div[@id=”list1”]/li[2]Div2 li1//div[@id=”list2”]/li[1]Div2 li2//div[@id=”list2”]/li[2]同时获取所有li1或li2的相对路径(所有相同结构的均会被选出)元素xpathli1//li[@class=”li1”]li2//li[@class=”li2”]上⾯这种⽅式我⽐较常⽤于爬取⽂章时,直接写//p,然后再来进⾏筛选,因为p标签就是代表的段落。那么问题来了,我要获取的不是整个标签,⽽是详细的标签内容啊,或者说是标签的属性啊,⽐如innerHTML、href、src等等属性。接下来进⾏介绍如何获取到详细的属性。分为两个部分,⼀个是innerHTML(就是起始标签和终⽌标签中间的东西),⼀个是其他属性。InnerHTML使⽤ 节点/text() 来获取;其他属性使⽤ 节点/@属性名 来获取。例如各个li标签的innerHTML和class。元素innerHTMLclassDiv1 li1//div[@id=”list1”]/li[1]/text()//div[@id=”list1”]/li[1]/@classDiv1 li2//div[@id=”list1”]/li[2]/text()//div[@id=”list1”]/li[2]/@classDiv2 li1//div[@id=”list2”]/li[1]/text()//div[@id=”list2”]/li[1]/@classDiv2 li2//div[@id=”list2”]/li[2]/text()//div[@id=”list2”]/li[2]/@class获取a标签的href链接元素hrefa//a/@href上⾯这个⽅式经常⽤于从⼀个⽹页出发爬取相关链接时的第⼀步解析。在python中可使⽤lxml模块来将HTML源码转换为XML的树状结构以便进⾏xpath的路径查询。以上⽂中的html代码为例,分别解析出各个li标签的innerHTML和a标签的href,代码如下。import as ehtml = '''HTML解析⽰例list1的第⼀个listlist1的第⼆个listlist2的第⼀个listlist2的第⼆个list百度链接'''selector = (html)#获取li标签li = ('//li/text()')print(li)#获取a标签a = ('//a/@href')print(a)可以看出xpath提取后的结果均为列表(如果没有最后提取的属性,那么结果为节点,⽽该节点可以继续往后写xpath,不过这⾥最顶层的节点为当前节点,下⼀个例⼦中详细见代码)以百度新闻python爬⾍为例,需要提取第⼀页中的每⼀块内容的标题和链接,每⼀个标题和链接需要进⾏匹配(不能提取出20个标题和链接后挨个来进⾏匹配,很容易错位)代码如下。from t import Request,urlopenfrom import HTMLreq = Request('/ns?cl=2&rn=20&tn=news&word=python%E7%88%AC%E8%99%AB')_header('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/63.0.3239.132 Safari/537.36')html = urlopen(req).read().decode('utf-8')selector = HTML(html)nodes = ('//div[@id="content_left"]/div[3]/div')for node in nodes:result = {'title':('h3/a/text()'),'link':('h3/a/@href')}print(result)代码中⾸先定位到id为content_left的div,然后从该div往下找到每⼀个新闻内容的版块(每个版块的结果⼏乎是⼀模⼀样的),此时的节点已定位到了20个新闻内容的版块,故返回的nodes节点内有20个选择器(因还未提取出其属性,故该节点依旧还是选择器)。接下来使⽤⼀个循环,将每个新闻版块的标题和链接提取出来,放⼊同⼀个字典中(这样做就保证了⼀个标题对应⼀个链接,⼤⼤的降低了错位的可能性)。当然,获取到的结果是⼀个列表并不理想,还需要进⾏进⼀步的处理(其实使⽤字符串的拼接即可,不再赘述)02CSS选择器接下来介绍CSS选择器。CSS选择器顾名思义其实就是CSS粉刷匠定位元素的⽅式,写法和xpath有相似之处,功能也相似,但差别也很⼤(使⽤css选择器的最好是有前端基础的童鞋)。例如还是以上⽂中写的HTML代码,css选择器采⽤pyquery模块(其实⽆论是请求还是解析⽅法都太多太多了,前期到中期只需要挑⼀个喜欢的习惯的写就可以了)。from pyquery import PyQuery as pqhtml='''HTML解析⽰例list1的第⼀个listlist1的第⼆个listlist2的第⼀个listlist2的第⼆个list百度链接'''doc = pq(html)#获取所有li标签的innerHTMLli1 = doc('li').text()print(li1)#获取id为list1的div下的所有li标签的innerHTMLli2 = doc('#list1 > li').text()print(li2)#获取class为li1的li标签的innerHTMLli3 = doc('.li1').text()print(li3)#获取a标签的hrefhref = doc('a').attr('href')print(href)在css选择器中选择下⼀节点时可不写 > ,可直接打⼀个空格代表下⼀层,id属性直接⽤#来表⽰,class属性⽤⼀个 . 来表⽰。03正则表达其实写到这⾥不是太想写正则,因为我个⼈爬⾍的时候真的很难⽤到,但还是不能忘了本,勉强写⼀写吧(其实就是不想写正则⽽已T_T)。打滚。。代码如下import rehtml=r'''HTML解析⽰例list1的第⼀个listlist1的第⼆个listlist2的第⼀个listlist2的第⼆个list百度链接'''#获取每个li的innerHTMLli1 = l(r'(.+)', html,flags=0)for li in li1:print(li)print(li[1])print('==============================')#获取id为list1的div下的li的innerHTMLdiv = l(r'.+)',(r'[nt]','',html),flags=0)[0][1]li2 = l(r'(.+)',div)for li in li2:print(li[1])print('==============================')#获取a标签的hrefa = l(r'(.+)',html,flags=0)print(a[0][1])04bs4使⽤bs4模块中的BeautifulSoup来进⾏解析。需求同上。from bs4 import BeautifulSouphtml=r'''HTML解析⽰例list1的第⼀个listlist1的第⼆个listlist2的第⼀个listlist2的第⼆个list百度链接'''bs = BeautifulSoup(html)#获取每个li的innerHTMLli1 = l(name='li')for li in li1:print(t())print('=============================')#获取id为list1的div下的li的innerHTMLli2 = l(name='div',id='list1')[0].findAll(name='li')for li in li2:print(t())print('=============================')#获取a标签的hrefa = l(name='a')[0].attrs['href']print(a)每种解析⽅法都有其市场,都有⼈⽤,只是每个⼯程师都有着⾃⼰的偏好和特长⽽已,我最开始是使⽤的beautifulsoup,然后使⽤CSS选择器,再之后正则也写了⼏个⽉,现在更喜欢⽤xpath,还是那句青菜萝⼘各有所爱,都能够达到⽬标,这就⾜够了。关于解析⽅法本⽂主要做了⼀个列举,若想深⼊学习某种解析⽅法的朋友敬请留⾔,畅所欲⾔,倘若有需求会针对某种解析⽅法进⾏详细的讲解。⼈⽣苦短,我选python。
发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1687984872a63827.html
评论列表(0条)