前言:

在写requests请求的时候,经常会用到Xpath;但是,转到scrapy之后,同样使用Xpath,语法就经常报错!!这是什么原因?

正文:

解答:

这是因为,

Scrapy的XPath解析器是基于lxml库实现的,所以它支持XPath 1.0语法。

XPath 1.0是XPath的第一个版本,由W3C发布于1999年。它是一种用于在XML文档中选取节点和节点集的语言,提供了强大的表达能力和灵活性。XPath 1.0已经成为事实上的标准,并被广泛应用于各种XML处理工具和库中。

尽管XPath在后续版本中有一些更新和扩展(如XPath 2.0和XPath 3.0),但Scrapy目前仍然使用基于lxml的XPath解析器,该解析器基于XPath 1.0规范实现。这并不意味着Scrapy不支持XPath 2.0或XPath 3.0,只是在Scrapy中,你只能使用XPath 1.0语法来编写和执行XPath表达式。

区别:

Scrapy内置了一个基于lxml库的XPath解析器,因此在Scrapy中使用XPath时,基本上遵循了lxml的XPath语法和规则。然而,有几个区别需要注意:

1返回值类型:

Scrapy的response.xpath()方法返回的是SelectorList对象,而lxml的xpath()方法返回的是一个列表或单个结果。SelectorList对象是Scrapy自定义的一个类,它包装了XPath结果并提供了额外的方法来进行进一步的数据处理。

案例:

在Scrapy种使用xpath时,extract()和extract_first()方法的作用是从Selector对象中提取匹配到的结果并返回一个列表或单个结果。

extract()方法返回一个包含所有匹配结果的列表,即使只有一个匹配项。extract_first()方法返回匹配结果中的第一个元素,如果没有匹配结果则返回None。

在Scrapy中,response.xpath()方法返回的是SelectorList对象,它是Scrapy内部封装的一个列表结构,而不是lxml的Element对象。因此,在Scrapy中访问元素时需要使用这些方法来提取数据。

在lxml中,xpath()返回的是Element对象或ElementTree对象,所以你可以直接使用Element对象的方法来提取数据。

当你用Scrapy时,response.xpath()返回的是SelectorList对象,你可以使用extract()或extract_first()方法来提取数据。extract()方法将匹配到的所有结果提取到一个列表中,而extract_first()方法只提取第一个匹配结果。这使得在处理Scrapy的数据抓取过程中更加方便。

举个例子,假设我们有以下的HTML内容:

  • Item 1
  • Item 2
  • Item 3

如果你使用Scrapy,可以这样提取数据:

data = response.xpath('//li/text()').extract()

print(data)

# 输出:['Item 1', 'Item 2', 'Item 3']

first_item = response.xpath('//li/text()').extract_first()

print(first_item)

# 输出:'Item 1'

如果使用lxml,可以这样提取数据:

from lxml import html

tree = html.fromstring(html_content)

data = tree.xpath('//li/text()')

print(data)

# 输出:['Item 1', 'Item 2', 'Item 3']

first_item = tree.xpath('//li/text()')[0]

print(first_item)

# 输出:'Item 1'

总结

Scrapy的Selector对象和lxml的Element对象有一些区别,所以在提取数据时需要使用相应的方法进行处理。

2.属性选择器:

在Scrapy中,可以使用@符号来选择元素的属性。例如,response.xpath('//div/@class').extract()可以提取所有div元素的class属性。而在lxml中,属性选择器是通过[@attribute-name]来实现的。

案例:

当然,我可以为你提供一个Scrapy案例和一个XPath案例,以便更好地理解它们的应用。

Scrapy案例:

假设我们要爬取豆瓣电影Top 250的电影名称和评分。

import scrapy

class MoviesSpider(scrapy.Spider):

name = 'movies_spider'

allowed_domains = ['movie.douban.com']

start_urls = ['https://movie.douban.com/top250']

def parse(self, response):

movies = response.xpath('//ol[@class="grid_view"]/li')

for movie in movies:

title = movie.xpath('.//span[@class="title"]/text()').get()

rating = movie.xpath('.//span[@class="rating_num"]/text()').get()

yield {

'title': title,

'rating': rating

}

XPath案例:

假设我们有一个HTML文档如下:

Title

Some text.

现在,我们想要使用XPath提取div元素中的文本内容。

可以使用lxml库来实现,示例代码如下:

from lxml import etree

# 定义HTML文档

html = '''

Title

Some text.

'''

# 创建XPath解析器

parser = etree.HTMLParser()

# 解析HTML文档

tree = etree.fromstring(html, parser)

# 使用XPath提取文本内容

text = tree.xpath('//div[@class="container"]/text()')

# 输出结果

print(text)

运行上述代码,将输出:

['\n ', '\n ', 'Title', '\n ', 'Some text.', '\n ']

可以使用.strip()函数去除空白字符,以获取更干净的结果。

总结:

scrapy会在内置里面处理得比较感觉,xpath会比较繁琐一些!

3.命名空间:

Scrapy在XPath中默认使用了命名空间(namespace)处理。如果要使用XPath解析具有命名空间的XML或HTML文档,需要在XPath表达式中显式指定命名空间前缀。例如,response.xpath('//atom:entry', namespaces={'atom': 'http://www.w3.org/2005/Atom'})指定了一个名为atom的命名空间。

4.默认上下文:

Scrapy自动在XPath表达式中使用了默认上下文节点。在Scrapy中,response.xpath('//div')将在整个文档中查找div元素,而不仅仅是在当前节点下查找。

5.默认转义:

Scrapy自动执行XPath结果的转义。例如,如果网页中的文本内容包含了HTML实体字符(如 ),response.xpath('//text()').extract()将返回已经转义后的文本内容,而不会包含原始的实体字符。

6.匹配顺序:

Scrapy的XPath解析器遵循了广度优先搜索的匹配顺序,这意味着较早匹配到的元素将在结果中排在前面,相同深度的元素则按照它们在文档中的顺序排列。

总结

Scrapy的XPath解析器在语法上与lxml类似,但在返回值类型、属性选择器、命名空间、默认上下文、默认转义和匹配顺序等方面有一些细微的差别。熟悉这些区别将有助于你更好地使用Scrapy进行数据抓取和解析。

相关阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: