@TheFlappy

Как исправить 401 при парсинге?

import requests

url = 'https://proverkacheka.com/api/v1/check/get'

headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0'
}

data = {
        'fn': fn,
        'fd': fd,
        'fp': fp,
        'n': 1,
        's': s,
        't': t,
}

response = requests.post(url, headers=headers, data=data)


Получаю 200 при получении запроса, но в нем лежит {'code': 401, 'data': 'Не авторизован (не представился). Для доступа к запрашиваемому ресурсу требуется аутентификация.'}

Не знаю как адекватно парсить всё это дело, авторизация на сайте для получения данных не требуется. При этом форма на сайте отправляется с другого url (https://proverkacheka.com/). Но запрос поступает на url, который в коде.

Реализовал парсинг на селениуме, работает, но долго и костыльно.
  • Вопрос задан
  • 768 просмотров
Решения вопроса 1
@AWEme
Retard Soft Inc.
Если я правильно понял, то авторизация требуется из-за неправильного токена. В ответ приходит зашифрованный джсон, накидал расшифровку, надеюсь не сломается.
В вопросе вы пытаетесь получить ответ через "Реквизиты", но я сделал вариант через "Строка QR-кода". На сайте пример использования есть.
Из внешних зависимостей aiohttp(можно заменить на requests) и pycryptodome
Код
import json
import hashlib
import asyncio
import aiohttp
from Crypto.Cipher import AES

URL = "https://proverkacheka.com"
API = "/api/v1/check/get"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0",
    "Referer": "https://proverkacheka.com/",
    "Origin": "https://proverkacheka.com",
}


def compute_token(qrraw: str, qr: str) -> str:
    base = qrraw + qr

    d = "0"
    for i in range(10000):
        h = hashlib.md5((base + (d := str(i))).encode()).hexdigest()
        if len(h.split("0")) - 1 > 4:
            break
    return "0." + d


async def get_crypted_json(qrraw: str, qr: str) -> bytes:
    form = aiohttp.FormData()
    form.add_field(name="qrraw", value=qrraw)
    form.add_field(name="qr", value=qr)
    form.add_field(name="token", value=compute_token(qrraw, qr))

    async with aiohttp.ClientSession(headers=headers) as client:
        # Получаем куки
        await client.get(URL)

        response = await client.post(URL + API, data=form, headers={"Cookie": "ENGID=1.1"})

        if "+crypto" not in response.headers["Content-Type"]:
            raise ValueError("Invalid token")

        return await response.read()


async def main() -> None:
    basekey = "38s91"
    decryptkey = "f65nm"

    qrraw = "t=20201017T1923&s=1498.00&fn=9282440300669857&i=25151&fp=1186123459&n=1"
    qr = "3"
    crypted_json = await get_crypted_json(qrraw, qr)

    crypted_data, nonce = crypted_json[:-12], crypted_json[-12:]
    key = hashlib.sha256((basekey + decryptkey).encode()).digest()

    cipher = AES.new(key=key, mode=AES.MODE_GCM, nonce=nonce)
    decrypted_data = cipher.decrypt(crypted_data)

    # В plain_text присутствует какие-то лишние символы на конце, скорее всего паддинг для зашифровки. Не проверял.
    plain_text = decrypted_data.decode(errors="ignore")

    # Отрезаем лишние символы справа
    pt = plain_text[:plain_text.rfind("}") + 1]

    with open("decoded.json", "wt", encoding="utf-8") as fp:
        loaded = json.loads(pt)
        json.dump(loaded, fp, ensure_ascii=False, indent=4)


if __name__ == "__main__":
    asyncio.run(main())
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
yarkov
@yarkov
Помог ответ? Отметь решением.
авторизация на сайте для получения данных не требуется

Вам 401 код ни на что не намекает? Конечно же требуется. На сайте есть личный кабинет. Войдите, откройте devtools и смотрите куда какие запросы идут.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы