带有HTTPS和HTTP认证的pywikipedia机器人

3 投票
2 回答
1645 浏览
提问于 2025-04-15 13:30

我在让我的机器人登录公司内部网的MediaWiki时遇到了麻烦。我觉得这可能是因为维基被HTTP认证保护了。

以下是一些事实:

  1. 维基的根地址是:https://local.example.com/mywiki/
  2. 当我用浏览器访问这个维基时,会弹出一个窗口要求输入企业凭证(我猜这就是基本的访问认证)

这是我在user-config.py文件里的内容:

mylang = 'en'
family = 'mywiki'
usernames['mywiki']['en'] = u'Bot'
authenticate['local.example.com'] = ('user', 'pass')

这是我在mywiki_family.py文件里的内容:

# -*- coding: utf-8  -*-
import family, config

# The Wikimedia family that is known as mywiki
class Family(family.Family):
  def __init__(self):
      family.Family.__init__(self)
      self.name = 'mywiki'
      self.langs = { 'en' : 'local.example.com'}

  def scriptpath(self, code):
      return '/mywiki'

  def version(self, code):
      return '1.13.5'

  def isPublic(self):
      return False

  def hostname(self, code):
      return 'local.example.com'

  def protocol(self, code):
      return 'https'

  def path(self, code):
      return '/mywiki/index.php'

当我执行login.py -v -v时,得到的结果是:

urllib2.urlopen(urllib2.Request('https://local.example.com/w/index.php?title=Special:Userlogin&useskin=monobook&action=submit', wpSkipCookieCheck=1&wpPassword=XXXX&wpDomain=&wpRemember=1&wpLoginattempt=Aanmelden%20%26%20Inschrijven&wpName=Bot, {'Content-type': 'application/x-www-form-urlencoded', 'User-agent': 'PythonWikipediaBot/1.0'})):
(Redundant traceback info here)
urllib2.HTTPError: HTTP Error 401: Unauthorized

(我不太明白为什么它显示的是'local.example.com/w'而不是'/mywiki'。)

我以为它可能是在尝试向example.com认证,而不是example.com/wiki,所以我把认证那一行改成了:

authenticate['local.example.com/mywiki'] = ('user', 'pass')

但是我却收到了来自IIS的HTTP 401.2错误:

您没有权限使用您提供的凭证查看此目录或页面,因为您的网页浏览器发送了一个WWW-Authenticate头字段,而Web服务器没有配置为接受它。

如果有人能帮我解决这个问题,我将非常感激。

更新 在修复了我的family文件后,现在显示:

获取网站mywiki:en的信息 ('http错误', 401, '未授权', ) 警告:无法打开'https://local.example.com/mywiki/index.php?title=Non-existing_page&action=edit&useskin=monobook'。也许服务器或您的连接出现了问题。1分钟后重试...

我查看了一个普通的urllib2.urlopen调用的HTTP头,发现它使用的是WWW-Authenticate: Negotiate和WWW-Authenticate: NTLM。我在想urllib2和pywikipedia是否不支持这个?

更新 为帮助我解决这个问题增加了一个丰厚的悬赏。我可以使用python-ntlm进行认证。请问我该如何将其集成到pywikipedia中?

2 个回答

0

我猜你的问题是服务器需要基本认证,但你的客户端没有处理这个认证。Michael Foord 写了一篇不错的文章,讲的是如何在 Python 中处理 基本认证

你没有提供足够的信息让我确认这个问题,所以如果这样做不行,请提供一些额外的信息,比如你连接尝试时的网络数据记录。

4

首先,login.py 试图访问 '\w' 而不是你的路径,这说明你的家庭配置有问题。

你的代码缩进得很奇怪:scriptpath 是新 Family 类的成员吗?就像这样:

class Family(family.Family):
    def __init__(self):
        family.Family.__init__(self)
        self.name = 'mywiki'
        self.langs = { 'en' : 'local.example.com'}

    def scriptpath(self, code):
        return '/mywiki'

    def version(self, code):
        return '1.13.5'

    def isPublic(self):
        return False

    def hostname(self, code):
        return 'local.example.com'

    def protocol(self, code):
        return 'https'

?

我觉得你的家庭文件有问题。检查的方法很简单,可以在 Python 控制台里输入:

import wikipedia
site = wikipedia.getSite('en', 'mywiki')
print site.login_address()

只要相对地址不对,显示的是 '/w' 而不是 '/mywiki',就说明家庭文件还没有正确配置,这样机器人就无法正常工作了 :)

更新:如何在 pywikipedia 中集成 ntlm?

我刚看了下基本示例,在这里。我会在 login.py 中那行代码之前集成这段代码:

response = urllib2.urlopen(urllib2.Request(self.site.protocol() + '://' + self.site.hostname() + address, data, headers))

你想写的内容大概是这样的:

from ntlm import HTTPNtlmAuthHandler

user = 'DOMAIN\User'
password = "Password"
url = self.site.protocol() + '://' + self.site.hostname()

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, url, user, password)
# create the NTLM authentication handler
auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)

# create and install the opener
opener = urllib2.build_opener(auth_NTLM)
urllib2.install_opener(opener)

response = urllib2.urlopen(urllib2.Request(self.site.protocol() + '://' + self.site.hostname() + address, data, headers))

我会测试这个,并直接将其集成到 pywikipedia 的代码库中,只要我有可用的 ntlm 设置...

无论发生什么,请不要把你的解决方案藏起来:我们在 pywikipedia 非常感兴趣你的解决方案 :)

撰写回答