【问题标题】:How to extract raw html from a Scrapy selector?如何从 Scrapy 选择器中提取原始 html?
【发布时间】:2016-01-19 21:57:41
【问题描述】:

我正在使用 response.xpath('//*')re_first() 提取 js 数据,然后将其转换为 python 本机数据。问题是提取/重新方法似乎没有提供不取消引用 html 的方法,即

原始html:

{my_fields:['O'Connor Park'], }

提取输出:

{my_fields:['O'Connor Park'], }

将此输出转换为 json 将不起作用。

最简单的方法是什么?

【问题讨论】:

    标签: python scrapy parsel


    【解决方案1】:

    简答:

    • 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&#39;Connor Park']}
        </script>
    </div>
    </body>
    </html>
    

    使用scrapy Selector,它使用下面的parsel库,你有几种方法来提取Javascript sn-p:

    >>> import scrapy
    >>> t = """<html lang="en">
    ... <body>
    ... <div>
    ...     <script type="text/javascript">
    ...         var i = {a:['O&#39;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&#39;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&#39;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 实体 &amp;#39; 已替换为 apostrophe。这是由于在.re/re_first 实现中的w3lib.html.replace_entities() 调用(参见parsel 源代码,在extract_regex 函数中),在简单调用extract()extract_first() 时不会使用它

    【讨论】:

    • 优秀的答案! Scrapy 的文档使这些相关方法的不一致更加混乱。它不仅没有提到 html 实体,还提到了“未引用百分比编码内容”。仅通过 extract() 。有点暗示如果有什么提取是比 re() 进行更多解码的那个。
    【解决方案2】:

    您还可以使用 Selector 类的 extract 方法使用的相同函数,但参数不同:

    from lxml import etree
    etree.tostring(selector._root)
    

    【讨论】:

      【解决方案3】:

      从 parsel 1.2.0 (2017-05-17) 开始,您可以将 replace_entities=False 传递给 rere_first 以避免默认行为。

      【讨论】:

        猜你喜欢
        • 2012-03-08
        • 1970-01-01
        • 2019-10-05
        • 2010-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多