aiohttp: пытается подключиться к сайту - PullRequest
0 голосов
/ 25 января 2020

Я создаю Discord Bot в Python, чтобы очистить данные Hack The Box. Это уже работает, но я хочу использовать asyn c с aiohttp для увеличения скорости, когда я запрашиваю каждый профиль каждого члена.

Итак, в синхронной версии я сделал функцию входа, которая сначала делает запрос get, чтобы получить токен на странице входа в систему, а затем отправить запрос с токеном, адресом электронной почты и паролем.

А в асинхронной версии с aiohttp, когда я делаю запрос на публикацию, мой сеанс не подключен.

Я немного сократил его только для тестирования производительности:

import requests
import re
import json
from scrapy.selector import Selector
import config as cfg
from timeit import default_timer

class HTBot():
    def __init__(self, email, password, api_token=""):
        self.email = email
        self.password = password
        self.api_token = api_token

        self.session = requests.Session()
        self.headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36"
        }
        self.payload = {'api_token': self.api_token}

        if path.exists("users.txt"):
            with open("users.txt", "r") as f:
                self.users = json.loads(f.read())
        else:
            self.users = []


    def login(self):
        req = self.session.get("https://www.hackthebox.eu/login", headers=self.headers)

        html = req.text
        csrf_token = re.findall(r'type="hidden" name="_token" value="(.+?)"', html)

        if not csrf_token:
            return False

        data = {
            "_token": csrf_token[0],
            "email": self.email,
            "password": self.password
        }

        req = self.session.post("https://www.hackthebox.eu/login", data=data, headers=self.headers)

        if req.status_code == 200:
            print("Connecté à HTB !")
            self.session.headers.update(self.headers)
            return True

        print("Connexion impossible.")
        return False


    def extract_user_info(self, htb_id):
        infos = {}
        req = self.session.get("https://www.hackthebox.eu/home/users/profile/" + str(htb_id), headers=self.headers)

        if req.status_code == 200:
            body = req.text
            html = Selector(text=body)

            infos["username"] = html.css('div.header-title > h3::text').get().strip()
            infos["avatar"] = html.css('div.header-icon > img::attr(src)').get()
            infos["points"] = html.css('div.header-title > small > span[title=Points]::text').get().strip()
            infos["systems"] = html.css('div.header-title > small > span[title="Owned Systems"]::text').get().strip()
            infos["users"] = html.css('div.header-title > small > span[title="Owned Users"]::text').get().strip()
            infos["respect"] = html.css('div.header-title > small > span[title=Respect]::text').get().strip()
            infos["country"] = Selector(text=html.css('div.header-title > small > span').getall()[4]).css('span::attr(title)').get().strip()
            infos["level"] = html.css('div.header-title > small > span::text').extract()[-1].strip()
            infos["rank"] = re.search(r'position (\d+) of the Hall of Fame', body).group(1)
            infos["challs"] = re.search(r'has solved (\d+) challenges', body).group(1)
            infos["ownership"] = html.css('div.progress-bar-success > span::text').get()

            return infos

        return False


    def refresh_user(self, htb_id, new=False):
        users = self.users

        for user in users:
            if user["htb_id"] == htb_id:
                infos = self.extract_user_info(htb_id)


    def refresh_all_users(self):
        users = self.users

        for user in users:
            self.refresh_user(user["htb_id"])

            elapsed = default_timer() - START_TIME
            time_completed_at = "{:5.2f}s".format(elapsed)
            print("{0:<30} {1:>20}".format(user["username"], time_completed_at))

        print("Les users ont été mis à jour !")

htbot = HTBot(cfg.HTB['email'], cfg.HTB['password'], cfg.HTB['api_token'])
htbot.login()

START_TIME = default_timer()
htbot.refresh_all_users()

Затем мой асин c переписал только для функции входа в систему:

import asyncio
import re
import config as cfg

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36"
}

LOGIN_LOCK = asyncio.Lock()

async def login():
    async with LOGIN_LOCK:
        async with aiohttp.TCPConnector(share_cookies=True) as connector:
            async with aiohttp.ClientSession(connector=connector, headers=headers) as session:
                async with session.get("https://www.hackthebox.eu/login") as req:

                    html = await req.text()
                    csrf_token = re.findall(r'type="hidden" name="_token" value="(.+?)"', html)

                    if not csrf_token:
                        return False

                    payload = {
                        "_token": csrf_token[0],
                        "email": cfg.HTB['email'],
                        "password": cfg.HTB['password']
                    }

                async with session.post('https://www.hackthebox.eu/login', data=payload) as req:
                    print(await req.text())

                exit()


async def main():
    await login()

asyncio.run(main())

Я думаю, что захожу слишком далеко с этим BaseConnector, Locks et c, но я работаю над ним уже два дня и у меня заканчиваются идеи, я уже пытаюсь соединиться с этим постом request.

Я также сделал сравнение двух запросов с Requests и aiohttp в Wireshark. Разница лишь в том, что тот, у кого есть aiohttp, не отправляет keepalive и имеет куки. (Я уже пытался вручную установить заголовок «connection: keep-alive», но это ничего не меняет). Однако, согласно документации, keep-alive должен быть активен по умолчанию, поэтому я не понимаю.

(На экране 301 код состояния нормальный, для моих запросов HTTP, которые я имел использовать http вместо https.)

Экран Wireshark: https://files.catbox.moe/bignh0.PNG

Спасибо, если вы можете мне помочь!

Поскольку я новичок в асинхронном программировании, я приму все ваши советы. К сожалению, почти все, что я читал об этом в inte rnet, устарело для Python 3.7+ и не использует новые синтаксисы.

1 Ответ

0 голосов
/ 27 января 2020

Хорошо, я наконец-то переключился на httpx, и это сработало как шарм. Я действительно не знаю, почему aiohttp не будет работать.

...