BeautifulSoup 能查找 HTML 中的元素,而scrapy 中也有强大的查找 HTML 元素的功能。
那就是使用 xpath 方法。xpath 方法使用 XPath 语法,比BeautifulSoup 的 select 要灵活而且速度快。
举例:
from scrapy.selector import Selector
htmlText='''
<html><body>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
</body></html>
'''
selector=Selector(text=htmlText)
s=selector.xpath("//title")
selector=Selector(text=htmlText)
使用 htmlText 的文字建立 Selector 类,就是装载 HTML 文档,文档装载后就形成一个Selector 对象,就可以使用 xpath 查找元素。
语法
1、"//“与”/"的使用
使用"//“表示文档下面的所有节点元素,用”/"表示当前节点的下一级节点元素。
实例:
selector.xpath("//bookstore/book") 搜索<bookstore>
下一级的<book>
元素,找到 2 个;
selector.xpath("//body/book") 搜索<body>
下一级的<book>
元素,结果为空;
selector.xpath("//body//book") 搜索<body>
下<book>
元素,找到 2 个;
selector.xpath("/body//book") 搜索文档下一级的<body>
下的<book>
元素,找结果为空,因为文档的下一级是<html>
元素,不是<body>
元素;
selector.xpath("/html/body//book")或者 selector.xpath("/html//book") 搜索<book>
元素,找到 2 个;
selector.xpah("//book/title") 搜索文档中所有<book>
下一级的<title>
元素,找到 2 个,结果与 selector.xpah("//title")
、selector.xpath("//bookstore//title")
一样;
selector.xpath("//book//price")与 selector.xpath("//price")
结果一样,都是找到 2 个元素;
2、"."的使用
使用"."表示当前节点元素,使用 xpath 可以连续调用,如果前一个 xpath 返回一个
Selector 的列表,那么这个列表可以继续调用 xpath,功能是为每个列表元素调用 xpath,
最后结果是全部元素调用 xpath 的汇总。
selector.xpath("//book").xpath("./title")
是先搜索到文档中所有<book>
元素,然后是从当前元素开始往下一级搜索<title>
。
selector.xpath("//book").xpath("/title")
相比与上面少了 “.”,表示先搜索到文档中所有<book>
元素,然后是从头开始搜索所有下一级节点<title>
。
3、extract()函数
xpath 返回的 Selector 对象列表,再次调用 extract()函数会得到这些对象的元素文本的列表,使用 extract_first()获取列表中第一个元素值,如果列表为空 extract_first()的值为 None。
对于单一的一个 Selector 对象,调用 extract()函数就可以得到 Selector 对象对应的元素的文本值。单一的 Selector 对象没有 extract_first()函数。
举例:
from scrapy.selector import Selector
htmlText='''<html> <body> <bookstore> <book id="b1">
<title lang="english">Harry Potter</title>
<price>29.99</price>
</book> <book id="b2">
<title lang="chinese">学习 XML</title>
<price>39.95</price>
</book>
</bookstore>
</body></html>'''
s=selector.xpath("//book/price") 得到的是 SelectorList 列表;
s=selector.xpath("//book/price").extract() 得到的是<price>
元素的 Selector 对象对应的<price>
元素的文本组成的列表,即:['<price>29.99</price>', '<price>39.95</price>']
s=selector.xpath("//book/price").extrac_first() 得到的是<price>
元素的文本组成的列表的
第一个元素,是一个文本,即:<price>29.99</price>
4、@attrName
xpath 使用"/@attrName"得到一个 Selector 元素的 attrName 属性节点对象,属性节点对象也是一个 Selector 对象,通过 extract()获取属性值。
5、/text()
xpath 使用"/text()"得到一个 Selector 元素包含的文本值,文本值节点对象也是一个Selector 对象,通过 extract()获取文本值。
如:s=selector.xpath("//book/title/text()"); print(s)
查询结果:[<Selector xpath='//book/title/text()' data='Harry Potter'>, <Selector xpath='//book/title/text()' data='学习 XML'>
]
s.extract():结果是文本节点的字符串值的列表,即[‘Harry Potter’, ‘学习 XML’]
是如果一个 element 的元素包含的文本不是单一的文本,那么可能会产生多个文本值。
6、tag[condition]
xpath 使用"tag[condition]"来限定一个 tag 元素,其中 condition 是由这个 tag 的属性、文本等计算出的一个逻辑值。
如果有多个条件,那么可以写成:“tag[condition1][condition2]…[conditionN]”
或者:“tag[condition1 and condition2 and … and conditionN]”
也可以使用and和or等符号构成复杂表达式
7、position()
xpath 可以使用 position()来确定其中一个元素的限制,这个选择序号是从 1 开始的,不是从 0 开始编号的,还可以通过 and、or 等构造复杂的表达式。
8、" * "
xpath 使用星号"*"代表任何 Element 节点,不包括 Text、Comment 的节点。
如:s=selector.xpath("//bookstore/*/title")表示搜索<bookstore>
的孙子节点<title>
,中间隔开一层任何元素。
9、 @*
xpath 使用"@*"代表任何属性
如:s=selector.xpath("//book[@*]/title")表示搜索任何包含属性的<book>
元素下面的<title>
10、父节点
xpath 使用element/parent::*
选择 element 的父节点,这个节点只有一个。
如果写成 element/parent::tag,就指定 element 的 tag 父节点,除非 element 的父节点正好为><tag>
节点,不然就为 None。
11、兄弟节点
11.1 following-sibling
xpath 使用"element/folllowing-sibling::*
"搜索 element 后面的同级的所有兄弟节点,
使用"element/folllowing-sibling::*[position()=1]
" 搜索 element 后面的同级的第一个兄弟节点。
如:s=selector.xpath("//b[position()=1]/following-sibling::*[position()=1]")
是搜索第一个<b>
节点后面的第一个兄弟节点,即<c>C1</c>
节点。
11.2 preceding-sibling
xpath 使用"element/preceding-sibling::*
"搜索 element 前面的同级的所有兄弟节点,
使用"element/preceding-sibling::*[position()=1]
" 搜索 element 前面的同级的第一个兄弟节点。
举例:
from scrapy.selector import Selector
htmlText="<a>A1</a><b>B1</b><c>C1</c><d>D<e>E</e></d><b>B2</b><c>C2</c>"
selector=Selector(text=htmlText)
s=selector.xpath("//b/preceding-sibling::*[position()=1]")
#搜索的是所有<b>前面的第一个兄弟节点,有 2 个<b>节点
#结果是['<a>A1</a>','<d>D<e>E</e></d>']
12、部分属性值匹配
lis = selector.xpath("//li['@ddt-pit'][starts-with(@class,'line')]")
表示匹配属性class的以line开头的属性值的元素。
lis = selector.xpath("//li['@ddt-pit'][ends-with(@class,'line')]")
表示匹配属性class的以line结尾的属性值的元素。
lis = selector.xpath("//li['@ddt-pit'][contains(@class,'line')]")
表示匹配属性class的包含line的属性值的元素。
By.xpath("//input[@*=‘fuck’]"))//匹配所有input元素中含有属性的值为fuck的元素元素。
————————————
以上。