Xpath CSS Selector

xpath 和 css selector 方式的内容提取介绍

1.定位元素

在目标网页中,找到相应的元素,右键检查元素,看到元素的代码信息,找到自己需要的,进行右击,这时候有两种方式可以获得标签的位置的具体描述方式:

  1. 使用 copy selector
  2. 使用 copy XPath

图示:

Xpath CSS Selector

 

这两种复制的路径有什么区别(以tr为例)?

copy XPath复制出来的路径:

/html/body/section/section/section/article/table[1]/tbody/tr[1]

copy selector复制出来的:

body > section > section > section > article >

table.table.table-striped.table-top20 > tbody > tr:nth-child(1)

这两种不同的路径描述方式,使用copy selector复制出来的路径叫做 CSS Selector,使用copy XPath复制出来的叫做XPath。

总之:

  1. XPath的路径是按照:谁,在哪,第几个的选择方式
  2. CSS Selector是按照:谁,在哪,第几个,长啥样来选择

3.内容提取方式一Xpath语言

XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言(并不是解析器!是一种语言格式),可用来在 XML 文档中对元素和属性进行遍历。

一般xpath要配合lxml解析器来使用。

XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。

*表示通配符。匹配任意节点

@*匹配节点中的任何属性

使用“ | ”运算符,选取若干个路径。

注意:

/ 和 // 的区别: / 代表只获取直接子节点; //获取子孙节点。

一般// 用的比较多。

./表示当前节点下,//表示全网页。

XPath语法——选取节点:

Xpath CSS Selector

 

路径表达式类似这种:

/html/body/div[4]/div[2]/div/div[2]/div[14]/a

或者

/html/body/div[@class=”content”] ,

其中第一个路径叫绝对路径,其中每个‘/’就是一个节点。

第二个路径中的[@class=”content”] 是为了在多个相同标签中定位到一个标签。

Xpath CSS Selector

 

在浏览器里面怎么找到你要的内容对应的xpath路径呢?

使用方法:

f12审查元素进去,然后直接在你需要爬的网页上面,找到你想要提取的对应地点,然后点击copy,copy xpath。

Xpath CSS Selector

 

复制出来的xpath语言是这样的:

//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[2]

那么怎么知道复制出来的xpath正不正确呢?

推荐两个xpath的插件。

在Chrome或Firefox浏览器中,有这样两个关于xpath的插件。可以快速找到对应网页的xpath路径。

  1. Chrome插件 XPath Helper
  2. Firefox插件 XPath Checker

插件使用效果:

当然你也可以直接在这个地方输入,ctrl+F,然后输入:

 

最后要注意的就是:使用.xpath() 的时候,其返回值是一个列表list,取值时需要注意。

4.内容提取方式—Css Selector

BeautifulSoup解析网页后,开始提取需要的内容,常用:Css Selector的方式。

BeautifulSoup本身不支持XPath表达式,可以用Css Selector的方式。

BeautifulSoup库有三种方法来查找元素。

  1. findall() 查找所有节点
  2. find() 查找单个
  3. selsect() 根据css的选择器Selector来查找

现在推荐的,就是第三种方式,根据css的选择器Selector来查找。

复制出来的 CSS Selector路径是这样的:

#app > div > div.tags-panel > ul > li:nth-child(1) > ul > li:nth-child(2)

同样也可以在浏览器里面验证你的CSS Selector路径是否正确?

ctrl+F 然后搜索自动匹配一下,找对了就会高亮。

 

BeautifulSoup结合Css Selector的爬虫提取例子:

import requests

from bs4 import BeautifulSoup

 

url = 'https://maoyan.com/films'

headers = {

    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'

}

response = requests.get(url, headers=headers)

if response.status_code == 200:

    soup = BeautifulSoup(response.text, 'html.parser') #也可用lxml

 

    # 获取文本,由于select()方法获得是list类型,必须要先获取到确定的元素,才能确定文本内容

    a1 = soup.select('body > div.header > div > div.city-container > div.city-selected')[0].get_text()

    print('Selector方式获取文本内容:',a1)

    a2 = soup.select('.city-name')[0].get_text()  # 按照标签名,id名,类名查找

    print('按标签名,id名,类名查询:',a2)

    a3 = soup.select('div .js-geo-city')  # 组合查找名为jsxxx的div。用空格分开

    print('组合查找:',a3)

   

# 查img的src,a标签中的href属性

    a4 = soup.select('div.movie-item > a > div > img:nth-of-type(2)')[0]['data-src']

    print('找img的src属性:',a4)

    # 重复li取其中一项:

    a5 = soup.select('div.channel-detail.channel-detail-orange')[0].get_text()

    print('重复li取其中一项:',a5)

 

    # 批量查询,比如table中多组td,div中多组li

    a6 = soup.select('body > div.header > div > div.nav > ul > li')

    for li in a6:

        # print(li)

        a = li.find('a')['href']

        # print(a)

        wz = li.text

        print('批量查找:',wz)

    # 与find方法对比-多但是copy快。

    a3111 = soup.find('div', class_='city-name').text

    print('与find方法对比:',a3111)

else:

    print('error', response.status_code)

常用的就是如下的了:

  1. 获取某个节点的文字:比如p标签外面的文字,标题
  2. 获取某个节点的属性值:比如a标签的href,img的src。
  3. 获取某个指定名称的点的文本内容或者属性:比如某个class='city-name’的div的内容。
  4. 批量获取列表型内容,比如table的多个td,div的多个li。

5.网页解析器lxml库

除了BeautifulSoup解析器以外,还有 lxml 也是python的一个解析库,而且解析效率非常高,支持HTML或XML的解析,支持使用Xpath1.0语法来解析代码。

主要的功能是如何解析和提取 HTML/XML 的数据。

注意:lxml和上面说的两种,xpath和css selector不是同一个类别。这是和BeautifulSoup一个级别的解析器。

使用 pip 安装:pip install lxml

代码使用的时候,主要是lxml的etree库来解析:

from lxml import etree 

利用lxml来 解析HTML代码,在解析HTML代码的时候,如果HTML代码不规范,他会自动的进行补全。

比如:

# 先安装lxml: pip install lxml

 

from lxml import etree  # 用lxml来解析HTML代码-自动补全

text='''

<div>

    <ul>

         <li class="item-0"><a href="link1.html">first item</a></li>....

'''

# 利用 etree.HTML 把字符串解析成 HTML 文件

html = etree.HTML(text)

# 按字符串序列化HTML文档

result = etree.tostring(html).decode()

print(result )

运行结果:

输出后,会补全了li标签,还添加了body,html标签。

 

因为lxml支持xpath,而且lxml快,xpath获得也非常方便,所以,我们

一般采用 “lxml+xpath” 的方式 来快速的定位特定元素以及节点信息。

( lxml+Selector也可以,但是推荐用xpath)

5.1 lxml 结合 xpath的常用方式:

使用xpath语法。应该使用Element.xpath方法。来执行xpath的选择。

示例代码如下:

 trs = html.xpath("//tr[position()>1]")

xpath函数 返回来的永远是一个列表。

获取某个标签的属性:

href = html.xpath("//a/@href") # 获取a标签的href值

获取文本,是通过xpath中的text()函数。

示例代码如下:

address = tr.xpath("./td[4]/text()")[0]

在某个标签下,再执行xpath函数,获取这个标签下的子孙元素,那么应该在斜杠之前加一个点,代表是在当前元素下获取。

示例代码如下:

  address = tr.xpath("./td[4]/text()")[0]

xpath解析器下元素下标从1开始。

5.2 根据读取的对象不同—方式也不同:

1.修正HTML代码,补齐标签

from lxml import etree

html=etree.HTML(text) #Lxml库解析数据,为Element对象

result=etree.tostring(html) #此时可以自动修正HTML代码,补齐标签等等

2.读取本地的HTML文件

读取本地的HTML文件使用parse()方法

from lxml import etree

html=etree.parse(r"文件路径")

result=etree.tostring(html,pretty_print=True)

3.解析在线请求回来的HTML源码

使用requests获取HTML源码后,

html=etree.HTML(res.text)

result = etree.tostring(html).decode() #实现对其的解析

再次提醒:使用.xpath() 的时候,其返回值是一个列表list

5.3 lxml和xpath 爬虫的提取例子:

# xpath函数返回的是一个列表

str ="""

    <div class="wrapper">

        <i class="iconfont icon-back" id="back">马麻花</i>

        <a href="/" id="channel">新浪社会</a>

        <ul id="nav">

            <li><a href="http://domestic.firefox.sina.com/" title="国内">国内</a></li>

            <li><a href="http://world.firefox.sina.com/" title="国际">国际</a></li>

            <li><a href="http://mil.firefox.sina.com/" title="军事">军事</a></li>

            <li><a href="http://photo.firefox.sina.com/" title="图片">图片</a></li>

            <li><a href="http://society.firefox.sina.com/" title="社会">社会</a></li>

            <li><a href="http://ent.firefox.sina.com/" title="娱乐">娱乐</a></li>

            <li><a href="http://tech.firefox.sina.com/" title="科技">科技</a></li>

            <li><a href="http://sports.firefox.sina.com/" title="体育">体育</a></li>

            <li><a href="http://finance.firefox.sina.com/" title="财经">财经</a></li>

            <li><a href="http://auto.firefox.sina.com/" title="汽车">汽车</a></li>

        </ul>

        <i class="iconfont icon-liebiao" id="menu">张三丰</i>

    </div>

    """

 

from lxml import etree

 

html=etree.HTML(str)        #创建一个html对象

result1=html.xpath("//a/text()")    #获取所有a标签下的所有内容

print(result1)

result2=html.xpath("//a/@href")    #获取所有a标签下的所有内容

print(result2)

result3=html.xpath("//li/a/text()") #获取标签下的内容

print(result3)

result4=html.xpath('//a[@id="channel"]/text()') #获取带属性的标签的内容

print(result4)

result5=html.xpath("//li[position()<4]/a/text()") #选前三项

print(result5)

result6=html.xpath("//li[1]/a/text()")      #第一个

print(result6)

result7=html.xpath("//li[last()]/a/text()")      #最后一个last()-1倒数第二项

print(result7)

result8=html.xpath("//i[contains(@class,'iconfont')]/text()")   #class类中包含iconfont的取出来

print(result8)

效果:

 

补充几种常见情况:

遇到相同的字符开头的多个标签?

<li class="tag-1">需要的内容1</li>

<li class="tag-2">需要的内容2</li>

<li class="tag-3">需要的内容3</li>

想同时爬取时,不需要构造多个Xpath路径,通过 starts-with()便可以获取多个标签内容。

starts-with()如下:

contents = selector.xpath('//li[starts-with(@class,"tag")]/text() ')

当遇到标签套标签情况时,想同时获取文本内容:

<div class="red">需要的内容1

<h1>需要的内容2</h1>

</div>>

可以使用string(.)方法如下:

from lxml import etree

 

html2 = '''

<div class="red">需要的内容1

<h1>需要的内容2</h1>

</div>>

'''

 

selector = etree.HTML(html2)

content1 = selector.xpath('//div[@class="red"]')[0]

content2 = content1.xpath('string(.)')

print(content2)

string(.)方法可用于标签套标签情况。

总结:

  1. xpath 和 css selector 是同一类,都是用来定位元素的两种不同的路径。其中xpath比css selector更高效一些。BeautifulSoup和Lxml是同一类,都是解析网页的解析器。
  2. 对于网页解析器BeautifulSoup,它本身不支持XPath表达式,所以可以用Css Selector的方式。
  3. 对于网页解析器Lxml,它支持xpath表达式,也支持Css Selector的方式,推荐使用xpath的方式。

最后说两句:

lxml只支持xpath1.0,不支持xpath2.0,Xpath2.0支持正则匹配,而1.0不支持,但是目前很多功能用不到。(但是,我还真没找到关于XPATH 2.0的教程或项目实例。截止2019/11月。现在市面上的网页基本上都还是xpath1的。)

其他参考网站:

https://www.cnblogs.com/jjb1997/p/11234638.html

https://www.jianshu.com/p/1660003f40c8

https://www.cnblogs.com/yiyea/p/11446981.html

https://www.cnblogs.com/wsg-python/articles/10182177.html

https://www.cnblogs.com/liudi2017/articles/9158390.html

https://www.cnblogs.com/zhangxinqi/p/9210211.html#_label16

上一篇:Scrapy在Ubuntu下的安装与配置


下一篇:linux下安装lxml包