如何正确阅读包含.iter_内容的大块html?

2024-05-15 09:26:33 发布

您现在位置:Python中文网/ 问答频道 /正文

所以,我是一个非常业余的python程序员,但希望我将要解释的一切都有意义

我想刮一种叫做“10-K”的财务文件。我只是对整个文件的一小部分感兴趣。我尝试刮取的URL的一个示例是:https://www.sec.gov/Archives/edgar/data/320193/0000320193-20-000096.txt

现在,如果我以.txt格式下载此文档,它“仅”具有12mb的重量。因此,对于我的无知来说,这需要1-2分钟才能完成(即使我有一台像样的电脑)

我使用的原始代码:

from urllib.request import urlopen
url = 'https://www.sec.gov/Archives/edgar/data/320193/0000320193-20-000096.txt'

response = urlopen(url)
document = response.read()

在这之后,我基本上将整个文档划分为<DOCUMENT>data</DOCUMENT>部分,并使用for循环来搜索每个文档数据中是否存在一些关键字,如<strong>CONSOLIDATED BALANCE SHEETS,这些关键字告诉我,在我想要刮取的表中有一个关键字。所有这些都是以常规的方式进行的(如果需要,可以共享代码),因为我已经尝试过bs4和其他解析器,并且是我的底层应用程序的PITA。使用df.read_html()完成了表解析的正确文档

所以现在我的方法是:

import requests
KeyWord = b'<strong>CONSOLIDATED BALANCE SHEETS'
interesting_chunk = b''

document = requests.get(url)

for chunk in document.iter_content(10000):
     if KeyWord in chunk:
          interesting_chunk = chunk
     else:
          continue

在这之后,我搜索<DOCUMENT>的开始和结束

doc_start_pos = interesting_chunk.find(b'<DOCUMENT>')
doc_end_pos  = interesting_chunk[doc_start_pos:].find(b'</DOCUMENT>')

final_document = interesting_chunk[doc_start_pos:doc_end_pos]

这里的问题:

  • 关键字可以分为两块,所以我找不到它
  • 对于<DOCUMENT>开始和结束也是一样的,甚至这些都不会出现在块中

所以我考虑使用另一个字符串来保存循环中的前一个区块,所以如果我找到关键字,我仍然能够将前一个区块和当前区块相加,并找到文档的开始,最后,我可以继续迭代,直到下一个</DOCUMENT>

但对于拆分关键字的问题,Idk如何处理它。它是随机的,它是一个大文件,不太可能,但如果我使用小块,就没有那么困难了。如何避免在两个块之间分割关键字

还有IDK什么应该是块的最佳大小


Tags: 文件文档httpspostxturldatadoc
1条回答
网友
1楼 · 发布于 2024-05-15 09:26:33

至少在大多数情况下,通过互联网阅读文档所需的时间实际上与计算机的速度无关。最重要的决定因素是互联网连接的速度。另一个重要的决定因素是远程服务器响应您的请求的速度,这部分取决于远程服务器当前尝试处理的其他请求的数量

也可能不是由于上述原因,而是由于远程服务器为限制刮取或避免拥塞而采取的措施。服务器故意降低对频繁请求的客户端的响应,甚至完全拒绝请求,这是很常见的。或者降低每个人的数据传输速度,这是控制服务器负载的另一种方法。在这种情况下,您将无法加快读取请求的速度

从我的机器上下载12MB的文档需要不到30秒的时间。由于我在佩鲁,互联网连接的速度可能是一个因素,但我怀疑这不是唯一的问题。然而,数据传输确实开始得相当快

如果问题与您的计算机和服务器之间的数据传输速度有关,您可以使用流式解析器(您可以搜索的短语)来加快速度。流式解析器以小块的形式读取其输入,并动态地将它们组合成令牌,这基本上就是您要做的。但是流解析器将透明地处理最困难的部分,即避免令牌在两个块之间分割。然而,SEC文档的性质(从整体上看不是非常纯的HTML)可能会使使用标准工具变得困难

由于您要分析的文档部分已经过了中间阶段,至少在您介绍的示例中是这样,因此您无法将下载时间减少很多。但这可能仍然是值得的

您描述的基本方法是可行的,但是您需要对其进行一些更改,以便处理在块之间分割的搜索字符串,正如您所指出的。基本思想是追加连续的块,直到找到字符串为止,而不是一次只看一个

我建议首先确定整个文档,然后决定它是否是您想要的文档。这将搜索问题简化为单个字符串,即文档终止符(\n</DOCUMENT>\n;添加换行符以减少错误匹配的可能性)

这是一个非常粗糙的实现,我建议您将其作为示例,而不是将其复制到您的程序中。函数docs从url生成连续的完整文档;调用者可以使用它来选择他们想要的。(在示例代码中,使用了第一个匹配文档,尽管在整个文件中实际上有两个匹配项。如果您想要所有匹配项,那么您必须读取整个输入,在这种情况下,您将不会有任何加速,尽管您可能会因为不必解析所有内容而节省一些成本。)

from urllib.request import urlopen
def docs(url):
    with urlopen(url) as f:
        buff = b''
        fence = b'\n</DOCUMENT>\n'
        while True:
            chunk = f.read(65536)
            if not chunk: break
                start = max(0, len(buff) - len(fence))
                buff += chunk
                end = buff.find(fence, start)
                if end != -1: 
                    end += len(fence)
                    yield buff[find(buff, b'<DOCUMENT>'):end]
        buff = buff[end:]

url = 'https://www.sec.gov/Archives/edgar/data/320193/0000320193-20-000096.txt'
keyword = b'<strong>CONSOLIDATED BALANCE SHEETS'

for document in docs(url):
    if keyword in document:
        # Process document
        break

相关问题 更多 >