在Stack Overflow上标记帖子时,获取"您无权标记此帖子"

iBu*_*Bug 5 python bots python-requests

我正在尝试开发一个能够在Stack Overflow上标记帖子的机器人.

from stackoverflow import StackOverflow
aaa = StackOverflow()
aaa.login("some email", "some password")
aaa.login_site()
response = aaa.add_flag(random_answer, "AnswerNotAnAnswer")
print(response.json())
Run Code Online (Sandbox Code Playgroud)

当然,您希望在.login()通话中替换电子邮件和密码,并替换random_answer为真实的答案ID.

我得到的结果是:

{'Success': False, 'Message': 'You do not have permission to flag this post', 'ResultChangedState': False, 'Outcome': 2}
Run Code Online (Sandbox Code Playgroud)

我还尝试使用浏览器登录并手动标记帖子.响应(在F12控制台中)是正确的:

{"Success":true,"Message":"Thanks, we'll take a look at it","FlagType":17,"ResultChangedState":false,"Outcome":0}
Run Code Online (Sandbox Code Playgroud)

简而言之,我正在尝试使用Stack Exchange OpenID登录,登录到Stack Overflow,并向其发送POST请求/flags/posts/<post_id>/add/<flag_type>.


这是代码(MCVE)的一部分,文件名stackoverflow.py当然是.

import requests
from bs4 import BeautifulSoup

class StackOverflow:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "StackOverflow/0.dev (+/dev/null)",
        })
        self.host = "stackoverflow.com"
        self.root = "https://" + self.host
        self.fkey = None

    def get(self, url, data=None, headers=None, root=True):
        if root:
            url = self.root + url
        return self.session.get(url, data=data, headers=headers, timeout=5.0)

    def post(self, url, data=None, headers=None, root=True):
        if root:
            url = self.root + url
        return self.session.post(url, data=data, headers=headers, timeout=5.0)

    def get_soup(self, url, data=None, headers=None, root=True):
        response = self.get(url, data, headers, root)
        return BeautifulSoup(response.text, "html.parser")

    def login_site(self):
        return self._login_openid(
            'https://{}/users/login?returnurl=%2F'.format(self.host),
            'https://{}/users/authenticate'.format(self.host),
            {
                'oauth_version': "",
                'oauth_server': "",
                'openid_identifier': "https://openid.stackexchange.com/",
            })

    def login(self, email, password):
        return self._login_openid(
            'https://openid.stackexchange.com/account/login',
            'https://openid.stackexchange.com/account/login/submit',
            {'email': email, 'password': password})

    def _login_openid(self, fkey_url, post_url, data):
        fkey_soup = self.get_soup(fkey_url, root=False)
        fkey_input = fkey_soup.find('input', {'name': 'fkey'})
        if not fkey_input:
            raise ValueError("fkey not found")
        self.fkey = fkey_input['value']

        data['fkey'] = self.fkey
        response = self.post(post_url, data=data, root=False)
        return response

    def add_flag(self, post_id, flag_type="AnswerNotAnAnswer"):
        response = self.post("/flags/posts/{}/add/{}".format(post_id, flag_type), data={
            'fkey': self.fkey,
        }, headers={
            'Origin': "https://stackoverflow.com",
            'Referer': "https://stackoverflow.com/",
        }, root=True)
        return response
Run Code Online (Sandbox Code Playgroud)