【问题标题】:python scrapy won't extract <script> tagpython scrapy 不会提取 <script> 标签
【发布时间】:2021-06-30 16:06:10
【问题描述】:

我是 Scrapy 的新手,我的代码无法从 HTML 响应中提取所需的脚本标签。

每个请求的 HTML 响应都以以下结构开头,如浏览器开发者工具中所示(来自随机响应的示例,省略了 HTML 的其余部分,因为相关数据始终位于同一脚本标记上):

<html  xmlns="http://www.w3.org/1999/xhtml"><head><script src="/pje/a4j/g/3_3_3.Final/org/ajax4jsf/framework.pack.js" type="text/javascript"></script><script src="/pje/a4j/g/3_3_3.Final/org/richfaces/ui.pack.js" type="text/javascript"></script><link class="component" href="/pje/a4j/s/3_3_3.Finalorg/richfaces/renderkit/html/css/basic_classes.xcss/DATB/eAELXT5DOhSIAQ!sA18_" rel="stylesheet" type="text/css" /><link class="component" href="/pje/a4j/s/3_3_3.Finalorg/richfaces/renderkit/html/css/extended_classes.xcss/DATB/eAELXT5DOhSIAQ!sA18_" media="rich-extended-skinning" rel="stylesheet" type="text/css" /><link class="component" href="/pje/a4j/s/3_3_3.Final/org/richfaces/skin.xcss/DATB/eAELXT5DOhSIAQ!sA18_" rel="stylesheet" type="text/css" /><script id="org.ajax4jsf.queue_script" type="text/javascript">if (typeof A4J != 'undefined') { if (A4J.AJAX) { with (A4J.AJAX) {if (!EventQueue.getQueue('org.richfaces.queue.global')) { EventQueue.addQueue(new EventQueue('org.richfaces.queue.global',null,null)) };}}};</script><script type="text/javascript">window.RICH_FACES_EXTENDED_SKINNING_ON=true;</script><link class="user" href="/pje/stylesheet/estilos/bootstrap/bootstrap.min.css" rel="stylesheet" type="text/css" /><link class="user" href="/pje/stylesheet/dropzone/dropzone.css" rel="stylesheet" type="text/css" /><link class="user" href="/pje/stylesheet/estilos/richfaces/tema.css" rel="stylesheet" type="text/css" /><link class="user" href="/pje/stylesheet/padrao.css" rel="stylesheet" type="text/css" /><link class="user" href="/pje/stylesheet/autos-digitais.css" rel="stylesheet" type="text/css" /><script src="/pje/js/modernizr.custom.js" type="text/javascript"></script><script src="/pje/js/jquery-2.1.4.min.js" type="text/javascript"></script><script src="/pje/js/bootstrap/bootstrap.min.js" type="text/javascript"></script><script src="/pje/js/jquery.maskedinput.min.js" type="text/javascript"></script><script src="/pje/js/mousetrap/mousetrap.min.js" type="text/javascript"></script><script src="/pje/js/mousetrap/plugins/global-bind/mousetrap-global-bind.js" type="text/javascript"></script><script src="/pje/js/pje/menu.js" type="text/javascript"></script><script src="/pje/js/global.js" type="text/javascript"></script><script src="/pje/js/pje/autos-digitais.js" type="text/javascript"></script><link class="user" href="/pje/stylesheet/estilos/icomoon/style.css" rel="stylesheet" type="text/css" /><script src="/pje/js/jquery.maskMoney.js" type="text/javascript"></script><script src="/pje/js/pje.js" type="text/javascript"></script><script src="/pje/js/pjeOffice.js" type="text/javascript"></script><script src="/pje/js/signerApplet.js" type="text/javascript"></script></head><script>window.open('https://api-pjestorage.tjdft.jus.br/2021063010s/0709994-47.2021.8.07.0020-1625061173643-2414698-processo.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minio-pje%2F20210630%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210630T135253Z&X-Amz-Expires=120&X-Amz-SignedHeaders=host&X-Amz-Signature=3348dc1ce55f1306d4555fb04f933af24ce5fa0b9c2540f5493a04bc83143be5');</script>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core">

    <head>
        
    
    <title>0709994-47.2021.8.07.0020 &middot; Processo Judicial Eletr&ocirc;nico - 1&ordm; Grau</title>

我的目标是提取始终包含在这部分 HTML 响应中的 URL,在上面的示例中为:https://api-pjestorage.tjdft.jus.br/2021063010s/0709994-47.2021.8.07.0020-1625061173643-2414698-processo.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minio-pje%2F20210630%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210630T135253Z&X-Amz-Expires=120&X-Amz-SignedHeaders=host&X-Amz-Signature=3348dc1ce55f1306d4555fb04f933af24ce5fa0b9c2540f5493a04bc83143be5

我使用response.css("script").extract() 作为测试,打算使用 re 模块从提到的脚本标签中提取 URL,但是,由于某种原因,Scrapy 跳过了所需的标签并产生了以下内容(我省略了其余的列表,因为我只对提取提到的 URL 感兴趣,但 Scrapy 继续到下一个脚本标签,跳过我需要的那个):

'<script src="/pje/a4j/g/3_3_3.Final/org/ajax4jsf/framework.pack.js" type="text/javascript"></script>', '<script src="/pje/a4j/g/3_3_3.Final/org/richfaces/u
i.pack.js" type="text/javascript"></script>', '<script id="org.ajax4jsf.queue_script" type="text/javascript">if (typeof A4J != \'undefined\') { if (A4J.AJAX) { with (
A4J.AJAX) {if (!EventQueue.getQueue(\'org.richfaces.queue.global\')) { EventQueue.addQueue(new EventQueue(\'org.richfaces.queue.global\',null,null)) };}}};</script>',
 '<script type="text/javascript">window.RICH_FACES_EXTENDED_SKINNING_ON=true;</script>', '<script src="/pje/js/modernizr.custom.js" type="text/javascript"></script>',
 '<script src="/pje/js/jquery-2.1.4.min.js" type="text/javascript"></script>', '<script src="/pje/js/bootstrap/bootstrap.min.js" type="text/javascript"></script>', '<
script src="/pje/js/jquery.maskedinput.min.js" type="text/javascript"></script>', '<script src="/pje/js/mousetrap/mousetrap.min.js" type="text/javascript"></script>',
 '<script src="/pje/js/mousetrap/plugins/global-bind/mousetrap-global-bind.js" type="text/javascript"></script>', '<script src="/pje/js/pje/menu.js" type="text/javasc
ript"></script>', '<script src="/pje/js/global.js" type="text/javascript"></script>', '<script src="/pje/js/pje/autos-digitais.js" type="text/javascript"></script>',
'<script src="/pje/js/jquery.maskMoney.js" type="text/javascript"></script>', '<script src="/pje/js/pje.js" type="text/javascript"></script>', '<script src="/pje/js/p
jeOffice.js" type="text/javascript"></script>', '<script src="/pje/js/signerApplet.js" type="text/javascript"></script>', '<script type="text/javascript">\n\t//<![CDA
TA[\n\t(function($){\n\t\t  $(document).ready(function() {\n\t\t\tvar selector = \'dtInicioInputDate\';\n\n\t\t\t//Seleciona elemento por id\n\t\t\tvar $input = $("in
put[id$=\'" + selector + "\']");\n\t\t\t\n\t\t\tif($input.length < 1){\n\t\t\t\t//Seleciona elemento por class\n\t\t\t\t$input = $("input" + selector);\n\t\t\t}\n\t\t
\t\n\t\t\tif (\'99/99/9999\' == \'\') {\n\t\t\t\t$input.unmask();\n\t\t\t} else {\n\t\t\t\t$input.mask(\'99/99/9999\');\n\t\t\t}\n\t\t });\n\t})(jQuery_21);\n\t//]]>\
n\t</script>'

上面列表中的最后一个元素出现在所需的脚本标记之后(从 HTML 响应中省略,因为它与任务无关):

'<script type="text/javascript">\n\t//<![CDATA[\n\t(function($){\n\t\t  $(document).ready(function() {\n\t\t\tvar selector = \'dtInicioInputDate\';\n\n\t\t\t//Seleciona elemento por id\n\t\t\tvar $input = $("in
put[id$=\'" + selector + "\']");\n\t\t\t\n\t\t\tif($input.length < 1){\n\t\t\t\t//Seleciona elemento por class\n\t\t\t\t$input = $("input" + selector);\n\t\t\t}\n\t\t
\t\n\t\t\tif (\'99/99/9999\' == \'\') {\n\t\t\t\t$input.unmask();\n\t\t\t} else {\n\t\t\t\t$input.mask(\'99/99/9999\');\n\t\t\t}\n\t\t });\n\t})(jQuery_21);\n\t//]]>\
n\t</script>'

我也尝试过使用

pattern = re.compile(r"'(https://api-pjestorage.tjdft.jus.br/.+)'")
lst_find = re.findall(pattern=pattern, string=response.text)

但它返回一个空列表,即使当我将 HTML 复制为字符串并尝试它时模式正常工作,这表明所需的脚本标签不包含在“response.text”中,因为某种原因我不知道不明白。

如何获取完整的原始 HTML 文本以使用正则表达式,或者如何确保 response.css(或 xpath)将提取所需的脚本标签?

为什么 Scrapy 会跳过一个脚本标签而正确提取所有其他标签?

很遗憾,由于需要登录名和密码,我无法共享我要抓取的页面。

任何建议将不胜感激。对不起英语不好。

【问题讨论】:

    标签: python scrapy


    【解决方案1】:

    您从中抓取的 HTML 页面似乎包含格式错误的 HTML。例如,您有两个 &lt;html&gt; 元素和两个 &lt;head&gt; 元素。这种格式错误的 HTML 可能会阻止 scrapy 找到您的脚本。

    解决问题的更简单方法是纯粹通过字符串操作和正则表达式。

    1. 仅将 HTML 的第一行保存到变量 firstLine(在第一行换行符 \n 之前)。 firstLine = response.text.split('\n')[0]
    2. 应用您的正则表达式:
      lst_find = re.findall(pattern=pattern, string=firstLine)
      

    【讨论】:

    • 如何只保存 HTML 的第一行?似乎它会起作用。尝试使用 response.css("html::first-line").extract() 但它不起作用 (cssselect.xpath.ExpressionError: The pseudo-element ::first-line is unknown) 。感谢您的帮助。
    • firstLine = response.text.split('\n')[0]。答案已更新
    • 不幸的是,它不起作用,使用 firstLine = response.text.split('\n')[0] 保存 &lt;?xml version="1.0" encoding="ISO-8859-1"?&gt; 。我认为这是因为畸形排除了 response.text 中的第一个 html 元素
    • @MateusSoares 您的浏览器开发工具和response.text 提供了不同的结果。我认为从这里开始的最好方法是包含response.text 的 sn-p 并手动查找您的 URL。您还应该将 sn-p 上传到 pastebin.com 等网站。
    • 即使建议的解决方案不起作用,我也会接受答案,因为它可以正确识别问题。看来,要提取所需的数据,我必须以某种方式将格式错误的 HTML 完全转换为文本。我认为 Scrapy 无法自行完成任务,因为我需要提取的数据不包含在 response.text 中,我可以搜索的唯一标签是 &lt;script&gt;。也许我可以更改请求(这是FormRequest.from_response())以防止出现问题,但我不知道如何。 scrapy-selenium 是因为 JS 而想到的,尝试它有什么意义吗?
    猜你喜欢
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 2021-10-10
    • 2018-10-29
    • 2018-07-15
    • 1970-01-01
    相关资源
    最近更新 更多