使用 Python 请求获取 html?
Get html using Python requests?
我正在尝试自学一些基本的网络抓取。使用 Python 的请求模块,我能够为各种网站获取 html,直到我尝试了这个:
>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
我得到了:
而不是作为此页面来源的基本 html
>>> r.text
'\x1f\ufffd\x08\x00\x00\x00\x00\x00\x00\x03\ufffd]o\u06f8\x12\ufffd\ufffd\ufffd+\ufffd]...
>>> r.content
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xed\x9d]o\xdb\xb8\x12\x86\xef\xfb+\x88]\x14h...
我已经尝试了 get/post 的多种组合以及我可以从文档、SO 和其他示例中猜到的每种语法。我不明白我在上面看到的是什么,没能把它变成任何我能读懂的东西,也不知道如何得到我真正想要的东西。我的问题是,如何获得上述页面的 html?
有问题的服务器正在给你一个 gzipped 响应。服务器也非常崩溃;它发送以下 headers:
$ curl -D - -o /dev/null -s -H 'Accept-Encoding: gzip, deflate' http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F
HTTP/1.1 200 OK
Date: Tue, 06 Jan 2015 17:46:49 GMT
Server: Apache
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"><html xmlns="http: //www.w3.org/1999/xhtml" lang="en-US">
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3659
Content-Type: text/html
<!DOCTYPE..>
行 不是有效的 HTTP header。因此,Server
之后剩余的 header 秒被 忽略 。为什么服务器会插入尚不清楚;在很可能的情况下 WRCCWrappers.py
是一个 CGI 脚本,它不输出 headers 但在 doctype 行之后包含一个双换行符,欺骗 Apache 服务器在那里插入额外的 headers。
因此,requests
也没有检测到数据是 gzip-encoded。数据都在那里,你只需要解码它。或者你可以,如果它不是相当不完整的话。
work-around是告诉服务器不要压缩:
headers = {'Accept-Encoding': 'identity'}
r = requests.get(url, headers=headers)
并返回未压缩的响应。
顺便说一句,在 Python 2 上,HTTP header 解析器并不那么严格,并且设法声明文档类型 a header:
>>> pprint(dict(r.headers))
{'<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "dtd/xhtml1-transitional.dtd"><html xmlns="http': '//www.w3.org/1999/xhtml" lang="en-US">',
'connection': 'Keep-Alive',
'content-encoding': 'gzip',
'content-length': '3659',
'content-type': 'text/html',
'date': 'Tue, 06 Jan 2015 17:42:06 GMT',
'keep-alive': 'timeout=5, max=100',
'server': 'Apache',
'vary': 'Accept-Encoding'}
并且 content-encoding
信息保留下来,因此 requests
会如预期的那样为您解码内容。
此 URL 的 HTTP headers 现已修复。
>>> import requests
>>> print requests.__version__
2.5.1
>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
>>> r.text[:100]
u'\n<!DOCTYPE html>\n<HTML>\n<HEAD><TITLE>Monthly Average of Precipitation, Station id: 028815</TITLE></H'
>>> r.headers
{'content-length': '3672', 'content-encoding': 'gzip', 'vary': 'Accept-Encoding', 'keep-alive': 'timeout=5, max=100', 'server': 'Apache', 'connection': 'Keep-Alive', 'date': 'Thu, 12 Feb 2015 18:59:37 GMT', 'content-type': 'text/html; charset=utf-8'}
我会用更简单的方法解决这个问题。只需导入 html
库即可解码 HTML 个特殊字符:
import html
r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
print(html.unescape(r.text))
这里是一个使用 BeautifulSoup 库的例子。它“使从网页中抓取信息变得容易。”
from bs4 import BeautifulSoup
import requests
# request web page
resp = requests.get("http://example.com")
# get the response text. in this case it is HTML
html = resp.text
# parse the HTML
soup = BeautifulSoup(html, "html.parser")
# print the HTML as text
print(soup.body.get_text().strip())
结果
Example Domain
This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.
More information...
我正在尝试自学一些基本的网络抓取。使用 Python 的请求模块,我能够为各种网站获取 html,直到我尝试了这个:
>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
我得到了:
而不是作为此页面来源的基本 html>>> r.text
'\x1f\ufffd\x08\x00\x00\x00\x00\x00\x00\x03\ufffd]o\u06f8\x12\ufffd\ufffd\ufffd+\ufffd]...
>>> r.content
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xed\x9d]o\xdb\xb8\x12\x86\xef\xfb+\x88]\x14h...
我已经尝试了 get/post 的多种组合以及我可以从文档、SO 和其他示例中猜到的每种语法。我不明白我在上面看到的是什么,没能把它变成任何我能读懂的东西,也不知道如何得到我真正想要的东西。我的问题是,如何获得上述页面的 html?
有问题的服务器正在给你一个 gzipped 响应。服务器也非常崩溃;它发送以下 headers:
$ curl -D - -o /dev/null -s -H 'Accept-Encoding: gzip, deflate' http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F
HTTP/1.1 200 OK
Date: Tue, 06 Jan 2015 17:46:49 GMT
Server: Apache
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"><html xmlns="http: //www.w3.org/1999/xhtml" lang="en-US">
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3659
Content-Type: text/html
<!DOCTYPE..>
行 不是有效的 HTTP header。因此,Server
之后剩余的 header 秒被 忽略 。为什么服务器会插入尚不清楚;在很可能的情况下 WRCCWrappers.py
是一个 CGI 脚本,它不输出 headers 但在 doctype 行之后包含一个双换行符,欺骗 Apache 服务器在那里插入额外的 headers。
因此,requests
也没有检测到数据是 gzip-encoded。数据都在那里,你只需要解码它。或者你可以,如果它不是相当不完整的话。
work-around是告诉服务器不要压缩:
headers = {'Accept-Encoding': 'identity'}
r = requests.get(url, headers=headers)
并返回未压缩的响应。
顺便说一句,在 Python 2 上,HTTP header 解析器并不那么严格,并且设法声明文档类型 a header:
>>> pprint(dict(r.headers))
{'<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "dtd/xhtml1-transitional.dtd"><html xmlns="http': '//www.w3.org/1999/xhtml" lang="en-US">',
'connection': 'Keep-Alive',
'content-encoding': 'gzip',
'content-length': '3659',
'content-type': 'text/html',
'date': 'Tue, 06 Jan 2015 17:42:06 GMT',
'keep-alive': 'timeout=5, max=100',
'server': 'Apache',
'vary': 'Accept-Encoding'}
并且 content-encoding
信息保留下来,因此 requests
会如预期的那样为您解码内容。
此 URL 的 HTTP headers 现已修复。
>>> import requests
>>> print requests.__version__
2.5.1
>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
>>> r.text[:100]
u'\n<!DOCTYPE html>\n<HTML>\n<HEAD><TITLE>Monthly Average of Precipitation, Station id: 028815</TITLE></H'
>>> r.headers
{'content-length': '3672', 'content-encoding': 'gzip', 'vary': 'Accept-Encoding', 'keep-alive': 'timeout=5, max=100', 'server': 'Apache', 'connection': 'Keep-Alive', 'date': 'Thu, 12 Feb 2015 18:59:37 GMT', 'content-type': 'text/html; charset=utf-8'}
我会用更简单的方法解决这个问题。只需导入 html
库即可解码 HTML 个特殊字符:
import html
r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
print(html.unescape(r.text))
这里是一个使用 BeautifulSoup 库的例子。它“使从网页中抓取信息变得容易。”
from bs4 import BeautifulSoup
import requests
# request web page
resp = requests.get("http://example.com")
# get the response text. in this case it is HTML
html = resp.text
# parse the HTML
soup = BeautifulSoup(html, "html.parser")
# print the HTML as text
print(soup.body.get_text().strip())
结果
Example Domain
This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.
More information...