如何从 Scrapy 选择器中提取原始 html?
How to extract raw html from a Scrapy selector?
我正在使用 response.xpath('//*')re_first() 提取 js 数据,然后将其转换为 python 本机数据。问题是 extract/re 方法似乎没有提供不取消引用 html 的方法,即
原版html:
{my_fields:['O'Connor Park'], }
提取输出:
{my_fields:['O'Connor Park'], }
将此输出转换为 json 将不起作用。
最简单的解决方法是什么?
简答:
- Scrapy/Parsel 选择器的
.re()
和 .re_first()
方法替换 HTML 实体(<
、&
除外)
- 相反,使用
.extract()
或 .extract_first()
获取原始 HTML(或原始 JavaScript 指令)并使用 Python 的 re
提取字符串上的模块
长答案:
让我们看一个示例输入以及从 HTML.
中提取 Javascript 数据的各种方法
样本HTML:
<html lang="en">
<body>
<div>
<script type="text/javascript">
var i = {a:['O'Connor Park']}
</script>
</div>
</body>
</html>
使用下面使用 parsel 库的 scrapy 选择器,您可以通过多种方式提取 Javascript 片段:
>>> import scrapy
>>> t = """<html lang="en">
... <body>
... <div>
... <script type="text/javascript">
... var i = {a:['O'Connor Park']}
... </script>
...
... </div>
... </body>
... </html>
... """
>>> selector = scrapy.Selector(text=t, type="html")
>>>
>>> # extracting the <script> element as raw HTML
>>> selector.xpath('//div/script').extract_first()
u'<script type="text/javascript">\n var i = {a:[\'O'Connor Park\']}\n </script>'
>>>
>>> # only getting the text node inside the <script> element
>>> selector.xpath('//div/script/text()').extract_first()
u"\n var i = {a:['O'Connor Park']}\n "
>>>
现在,使用 .re
(或 .re_first
)你会得到不同的结果:
>>> # I'm using a very simple "catch-all" regex
>>> # you are probably using a regex to extract
>>> # that specific "O'Connor Park" string
>>> selector.xpath('//div/script/text()').re_first('.+')
u" var i = {a:['O'Connor Park']}"
>>>
>>> # .re() on the element itself, one needs to handle newlines
>>> selector.xpath('//div/script').re_first('.+')
u'<script type="text/javascript">' # only first line extracted
>>> import re
>>> selector.xpath('//div/script').re_first(re.compile('.+', re.DOTALL))
u'<script type="text/javascript">\n var i = {a:[\'O\'Connor Park\']}\n </script>'
>>>
HTML 实体 '
已被 apostrophe. This is due to a w3lib.html.replace_entities()
call in .re/re_first
implementation (see parsel
source code, in extract_regex
函数取代),仅在调用 extract()
或 extract_first()
您还可以使用与 Selector
class' extract
方法相同的函数,但参数不同:
from lxml import etree
etree.tostring(selector._root)
自 parsel 1.2.0 (2017-05-17) 起,您可以将 replace_entities=False
传递给 re
和 re_first
以避免默认行为。
我正在使用 response.xpath('//*')re_first() 提取 js 数据,然后将其转换为 python 本机数据。问题是 extract/re 方法似乎没有提供不取消引用 html 的方法,即
原版html:
{my_fields:['O'Connor Park'], }
提取输出:
{my_fields:['O'Connor Park'], }
将此输出转换为 json 将不起作用。
最简单的解决方法是什么?
简答:
- Scrapy/Parsel 选择器的
.re()
和.re_first()
方法替换 HTML 实体(<
、&
除外) - 相反,使用
.extract()
或.extract_first()
获取原始 HTML(或原始 JavaScript 指令)并使用 Python 的re
提取字符串上的模块
长答案:
让我们看一个示例输入以及从 HTML.
中提取 Javascript 数据的各种方法样本HTML:
<html lang="en">
<body>
<div>
<script type="text/javascript">
var i = {a:['O'Connor Park']}
</script>
</div>
</body>
</html>
使用下面使用 parsel 库的 scrapy 选择器,您可以通过多种方式提取 Javascript 片段:
>>> import scrapy
>>> t = """<html lang="en">
... <body>
... <div>
... <script type="text/javascript">
... var i = {a:['O'Connor Park']}
... </script>
...
... </div>
... </body>
... </html>
... """
>>> selector = scrapy.Selector(text=t, type="html")
>>>
>>> # extracting the <script> element as raw HTML
>>> selector.xpath('//div/script').extract_first()
u'<script type="text/javascript">\n var i = {a:[\'O'Connor Park\']}\n </script>'
>>>
>>> # only getting the text node inside the <script> element
>>> selector.xpath('//div/script/text()').extract_first()
u"\n var i = {a:['O'Connor Park']}\n "
>>>
现在,使用 .re
(或 .re_first
)你会得到不同的结果:
>>> # I'm using a very simple "catch-all" regex
>>> # you are probably using a regex to extract
>>> # that specific "O'Connor Park" string
>>> selector.xpath('//div/script/text()').re_first('.+')
u" var i = {a:['O'Connor Park']}"
>>>
>>> # .re() on the element itself, one needs to handle newlines
>>> selector.xpath('//div/script').re_first('.+')
u'<script type="text/javascript">' # only first line extracted
>>> import re
>>> selector.xpath('//div/script').re_first(re.compile('.+', re.DOTALL))
u'<script type="text/javascript">\n var i = {a:[\'O\'Connor Park\']}\n </script>'
>>>
HTML 实体 '
已被 apostrophe. This is due to a w3lib.html.replace_entities()
call in .re/re_first
implementation (see parsel
source code, in extract_regex
函数取代),仅在调用 extract()
或 extract_first()
您还可以使用与 Selector
class' extract
方法相同的函数,但参数不同:
from lxml import etree
etree.tostring(selector._root)
自 parsel 1.2.0 (2017-05-17) 起,您可以将 replace_entities=False
传递给 re
和 re_first
以避免默认行为。