用Python获取维基百科文章

40

我尝试使用Python的urllib获取维基百科文章:

f = urllib.urlopen("http://en.wikipedia.org/w/index.php?title=Albert_Einstein&printable=yes")           
s = f.read()
f.close()

然而,我没有收到HTML页面,而是收到以下响应:错误 - Wikimedia基金会:

Request: GET http://en.wikipedia.org/w/index.php?title=Albert_Einstein&printable=yes, from 192.35.17.11 via knsq1.knams.wikimedia.org (squid/2.6.STABLE21) to ()
Error: ERR_ACCESS_DENIED, errno [No Error] at Tue, 23 Sep 2008 09:09:08 GMT 

维基百科似乎会阻止非标准浏览器的请求。

有人知道如何解决这个问题吗?


3
维基百科不会阻止非标准浏览器发送的请求,但如果使用标准库发送请求且没有更改其用户代理,那么维基百科将会阻止该请求。 - svick
10个回答

51
你需要使用Python标准库中替代urlliburllib2来更改用户代理。
直接参考示例
import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
infile = opener.open('http://en.wikipedia.org/w/index.php?title=Albert_Einstein&printable=yes')
page = infile.read()

7
维基百科试图阻止屏幕爬虫程序的原因是他们的服务器需要大量工作将维基代码转换为HTML,而获取文章内容有更简单的方式。请勿使用网络爬虫程序,详情请见http://en.wikipedia.org/wiki/Wikipedia:Database_download#Please_do_not_use_a_web_crawler。 - Cerin
2
你不应该尝试使用像 Mozilla/5.0 这样的用户代理来冒充浏览器。相反,你应该使用带有一些联系信息的信息性用户代理 - svick

37

这并不是针对特定问题的解决方案,但你可能会对使用mwclient库(http://botwiki.sno.cc/wiki/Python:Mwclient) 感兴趣。使用它将会更加容易,尤其是因为你可以直接获取文章内容,无需解析html。

我自己已经在两个项目中使用过它,并且效果非常好。


4
建议使用第三方库来完成可以轻松用几行代码完成的任务并不明智。 - Florian Bösch
17
因为mwclient使用mediawiki API,所以不需要对内容进行解析。我猜原帖作者想要的是内容,而不是带有菜单等所有原始HTML代码。 - Hannes Ovrén

15

与其试图欺骗维基百科,你应该考虑使用他们的高级API


这将反过来仍然阻止使用库默认用户代理标头的urllib请求。因此,尽管API可能是与维基内容交互的更简单的方法,但OP仍将面临完全相同的问题,具体取决于OP的目标是什么。 - njsg

3
如果您想访问维基百科的内容(而不需要任何有关页面本身的特定信息),则应该直接调用index.php并在其中使用“action=raw”,以获取wikitext,例如:

'http://en.wikipedia.org/w/index.php?action=raw&title=Main_Page'

或者,如果您需要HTML代码,请使用“action=render”,例如:

'http://en.wikipedia.org/w/index.php?action=render&title=Main_Page'

你还可以使用“section=3”之类的方式定义一个部分以获取内容的一部分。

然后,你可以使用urllib2模块进行访问(如所选答案中建议的)。 但是,如果你需要有关页面本身的信息(例如修订),建议使用mwclient。

如果需要更多信息,请参考MediaWiki的常见问题


你好,如果我不知道章节编号是3,但我知道这个章节的标题是“名词”,如何获取该特定章节? - Raj

2

我通常使用的一般解决方案是使用Firefox访问页面,并使用诸如Firebug之类的扩展记录包括任何cookie在内的HTTP请求的所有细节。

在您的程序中(在这种情况下为Python),您应该尝试发送与Firefox中工作的请求尽可能相似的HTTP请求。这通常包括设置User-Agent、Referer和Cookie字段,但也可能有其他字段。


2

requests非常棒!

以下是如何使用 requests 获取 HTML 内容的方法:

import requests
html = requests.get('http://en.wikipedia.org/w/index.php?title=Albert_Einstein&printable=yes').text

完成!


1
请求带有 ?printable=yes 的页面会给你一个相对干净的整个 HTML 文档。?action=render 只会给你主体 HTML。通过 MediaWiki 操作 API 请求解析页面同样只会给你主体 HTML,但如果你想要更精细的控制,可以使用 action=parse,请参考解析 API 帮助 see parse API help
如果您只想获取页面的HTML以便渲染它,更快更好的方法是使用新的RESTBase API,该API返回一个缓存的HTML页面表示。在这种情况下,https://en.wikipedia.org/api/rest_v1/page/html/Albert_Einstein
截至2015年11月,您不必设置用户代理,但强烈建议这样做。此外,几乎所有维基媒体维基都需要HTTPS,因此请避免301重定向并进行https请求。

1
尝试更改您在请求中发送的用户代理标头,例如: User-Agent: Mozilla/5.0(X11;U;Linux i686;en-US;rv:1.9.0.1)Gecko/2008072820 Ubuntu/8.04(hardy)Firefox/3.0.1(Linux Mint)

1

您不需要模拟浏览器用户代理;任何用户代理都可以使用,只是不能使用空白的。


4
urllib和urllib2都发送用户代理。 - Teifion
2
s/blank/空白或默认值/ - 这个想法就是你应该通过用户代理头来识别你的机器人。这就是为什么他们会阻止 urllib 的默认头。 - njsg

0
import urllib
s = urllib.urlopen('http://en.wikipedia.org/w/index.php?action=raw&title=Albert_Einstein').read()

这对我来说似乎可以正常工作,而不需要更改用户代理。如果没有“action=raw”,它对我来说就无法工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接