我重新检查了我的代码,并查看了打开 URL 将 Web 数据传递到 Beautiful Soup 的类似操作,由于某种原因,我的代码虽然格式正确,但没有返回任何内容:

>>> from bs4 import BeautifulSoup

>>> from urllib3 import poolmanager

>>> connectBuilder = poolmanager.PoolManager()

>>> content = connectBuilder.urlopen('GET', 'http://www.crummy.com/software/BeautifulSoup/')

>>> content
<urllib3.response.HTTPResponse object at 0x00000000032EC390>

>>> soup = BeautifulSoup(content)

>>> soup.title
>>> soup.title.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'name'
>>> soup.p
>>> soup.get_text()
''

>>> content.data
a stream of data follows...

如图所示,很明显 urlopen() 返回一个 HTTP 响应,该响应由变量 content 捕获,它可以读取响应的状态,但在将其传递到 Beautiful Soup 后,Web 数据没有得到转换进入 Beautiful Soup 对象(变量 soup)。你可以看到我尝试读取一些标签和文本, get_text() 返回一个空列表,这很奇怪。

奇怪的是,当我通过 content.data 访问网络数据时,数据会显示出来,但它没有用,因为我无法使用 Beautiful Soup 来解析它。我的问题是什么?谢谢。

有帮助吗?

解决方案

如果你只是想抓取页面, requests 将获得您需要的内容:

from bs4 import BeautifulSoup

import requests
r = requests.get('http://www.crummy.com/software/BeautifulSoup/')
soup = BeautifulSoup(r.content)

In [59]: soup.title
Out[59]: <title>Beautiful Soup: We called him Tortoise because he taught us.</title>

In [60]: soup.title.name
Out[60]: 'title'

其他提示

urllib3 返回一个 Response 对象,其中包含 .data 其具有预加载的主体有效负载。

根据顶部快速入门 使用示例在这里, ,我会做这样的事情:

import urllib3
http = urllib3.PoolManager()
response = http.request('GET', 'http://www.crummy.com/software/BeautifulSoup/')

from bs4 import BeautifulSoup
soup = BeautifulSoup(response.data)  # Note the use of the .data property
...

其余的应该按预期工作。

--

关于原始代码中出了什么问题的一些信息:

你通过了整个 response 对象而不是主体有效负载。这通常应该没问题,因为 response object 是一个类似文件的对象, 除了 在这种情况下,urllib3 已经消耗了所有响应并为您解析它,因此没有什么可以处理的 .read(). 。这就像传递一个已经被读取的文件指针。 .data 另一方面将访问已经读取的数据。

如果您想将 urllib3 响应对象用作类似文件的对象,则需要禁用内容预加载,如下所示:

response = http.request('GET', 'http://www.crummy.com/software/BeautifulSoup/', preload_content=False)
soup = BeautifulSoup(response)  # We can pass the original `response` object now.

现在它应该按您的预期工作。

我知道这不是很明显的行为,作为 urllib3 的作者,我深表歉意。:) 我们计划制作 preload_content=False 有一天默认。也许不久的将来(我在这里打开了一个问题).

--

快速说明 .urlopen.request:

.urlopen 假设您将负责对传递给请求的任何参数进行编码。在这种情况下使用就可以了 .urlopen 因为您没有向请求传递任何参数,但一般来说 .request 将为您完成所有额外的工作,因此更加方便。

如果有人愿意为此改进我们的文档,我们将不胜感激。:) 请将 PR 发送至 https://github.com/shazow/urllib3 并将您自己添加为贡献者!

如图所示,很明显 urlopen() 返回一个 HTTP 响应,该响应由变量 content 捕获......

你叫什么 content 不是内容,而是您可以从中读取内容的类似文件的对象。BeautifulSoup 非常乐意接受这样的事情,但是将其打印出来用于调试目的并不是很有帮助。因此,让我们实际读取其中的内容,以便更容易调试:

>>> response = connectBuilder.urlopen('GET', 'http://www.crummy.com/software/BeautifulSoup/')
>>> response
<urllib3.response.HTTPResponse object at 0x00000000032EC390>
>>> content = response.read()
>>> content
b''

这应该很清楚地表明 BeautifulSoup 不是这里的问题。但继续:

…但是在传递到 Beautiful Soup 后,Web 数据不会转换为 Beautiful Soup 对象(变量 soup)。

是的,它确实。事实是 soup.title 给你 None 而不是提出 AttributeError 是很好的证据,但你可以直接测试它:

>>> type(soup)
bs4.BeautifulSoup

这绝对是一个 BeautifulSoup 目的。

当你通过时 BeautifulSoup 一个空字符串,您返回的确切内容将取决于它在幕后使用哪个解析器;如果它依赖于 Python 3.x stdlib,你会得到的是 html 节点为空 head, ,和空 body, ,没有别的。所以,当你寻找一个 title 节点,没有一个,你得到 None.


那么,如何解决这个问题呢?

作为 文档 说,您正在使用“提出请求的最低级别的呼叫,因此您需要指定所有原始详细信息。”这些原始细节是什么?老实说,如果您还不知道,您就不应该使用这种方法教您如何处理 urllib3 在你知道基础知识不会为你提供服务之前。

事实上,你真的不需要 urllib3 根本就在这里。只需使用Python自带的模块即可:

>>> # on Python 2.x, instead do: from urllib2 import urlopen 
>>> from urllib.request import urlopen
>>> r = urlopen('http://www.crummy.com/software/BeautifulSoup/')
>>> soup = BeautifulSoup(r)
>>> soup.title.text
'Beautiful Soup: We called him Tortoise because he taught us.'

我的美丽汤代码在一个环境(我的本地机器)中工作,并在另一个环境中返回空列表(Ubuntu 14服务器)。

我已经解决了我的问题更改了安装。 其他线程中的详细信息:

与美丽汤的html解析返回空列表

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top