用 Scrapy 在 JSON 中抓取 HTML

Scraping HTML inside JSON with Scrapy

我正在请求一个响应为 JSON 的网站:

{
    "success": true,
    "response": "<html>... html goes here ...</html>"
}

我已经看到了报废 HTML 或 JSON 的两种方法,但还没有找到如何在 JSON 内报废 HTML。是否可以使用 scrapy 来做到这一点?

一种方法是从 JSON 数据中的 HTML 构建一个 scrapy.Selector

我假设您有 Response 对象,其中包含 JSON 数据,可通过 response.text 获得。

(下面,我正在构建一个测试响应来玩(我正在使用带有 Python 3 的 scrapy 1.1):

response = scrapy.http.TextResponse(url='http://www.example.com/json', body=r'''
{
    "success": true,
    "response": "<html>\n <head>\n  <base href='http://example.com/' />\n  <title>Example website</title>\n </head>\n <body>\n  <div id='images'>\n   <a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>\n   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>\n   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>\n   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>\n   <a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>\n  </div>\n </body>\n</html>"
}
''', encoding='utf8')

)

使用 json 模块你可以获得这样的 HTML 数据:

import json
data = json.loads(response.text)

你得到类似的东西:

>>> data
{'success': True, 'response': "<html>\n <head>\n  <base href='http://example.com/' />\n  <title>Example website</title>\n </head>\n <body>\n  <div id='images'>\n   <a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>\n   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>\n   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>\n   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>\n   <a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>\n  </div>\n </body>\n</html>"}

然后你可以像这样构建一个新的选择器:

selector = scrapy.Selector(text=data['response'], type="html")

之后您可以在其上使用 XPath 或 CSS 选择器:

>>> selector.xpath('//title/text()').extract()
['Example website']

你可以尝试 json.loads(initial_response) ,所以你得到一个字典并可以使用他的键,比如 ['response']

好吧,还有另一种方法,您绝对不需要构造响应 object.You 可以使用 lxml 来解析您的 html 文本。你不需要安装任何新的库,因为 Scrapy Selector 是基于 lxml 的。只需将下面的代码添加到 import lxml lib.

from lxml import etree

这是一个例子,假设 json 响应是:

{
    "success": true,
    "htmlinjson": "<html><body> <p id='p1'>p111111</p> <p id='p2'>p22222</p> </html>"
}

通过以下方式从 json 响应中提取 html 文本:

import json

htmlText = json.loads(response.text)['htmlinjson']

然后构造一个 lxml xpath 选择器使用:

from lxml import etree

resultPage = etree.HTML(htmlText)

现在使用 lxml 选择器提取 id="p1" 节点

的文本,基于 xpath 就像 scrapy xpath 选择器做的那样:

print resultPage.xpath('//p[@id="p1"]')[0].text

您将获得:

p111111

希望对您有所帮助:)