Возникают проблемы с поддержанием порядка заголовков сеансов при выполнении запроса - PullRequest
1 голос
/ 18 января 2020

Пользователь форума предложил мне, чтобы во избежание обнаружения мне нужно было поддерживать тот же порядок заголовков, что и в моем браузере. Я посмотрел на предложение здесь:

Python HTTP-запрос с контролируемым упорядочением заголовков HTTP

Однако, несмотря на попытки предложения, порядок меняется. Я не могу понять, что я делаю неправильно (обратите внимание, что повар ie заканчивается в конце):

import requests
import webbrowser
from bs4 import BeautifulSoup
import re
from collections import OrderedDict


BASE_URL = 'https://www.bloomberg.com/'
HEADERS = OrderedDict({'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
           'Accept-Encoding': 'gzip, deflate, br',
           'Cache-Control': 'max-age=0',
           'Connection': 'keep-alive',
            'Cookie': '',
            'Host': 'www.bloomberg.com',
            'Origin' : 'https://www.bloomberg.com',
            'Referer': 'https://www.bloomberg.com/',
             'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0',

           })




def latest_news():
        session = requests.Session()
        session.headers = HEADERS
##        session.headers['User-Agent'] = HEADERS['User-Agent']
##        session.headers['Referer'] = HEADERS['Referer']
##        #session.headers['Origin'] = HEADERS['Origin']
##        session.headers['Host'] =   HEADERS['Host'] 

        page = session.get(BASE_URL, allow_redirects = True)
        print(page.url)
        print(page.request.headers)
        print(page.history)
        page.raise_for_status()
        soup = BeautifulSoup(page.content, 'html.parser')
        print(soup)

if __name__ == "__main__":

    latest_news()

ВЫХОД:

 https://www.bloomberg.com/tosv2.html?vid=&uuid=e5737f50-3975-11ea-b7bd-97b9265w12w5&url=Lw==


#Request Headers      

{'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
     'Accept-Encoding': 'gzip, deflate, br', 
    'Cache-Control': 'max-age=0',
     'Connection': 'keep-alive', 
    'Host': 'www.bloomberg.com', 
    'Origin': 'https://www.bloomberg.com', 
    'Referer': 'https://www.bloomberg.com/',
     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0)
     Gecko/20100101 Firefox/64.0', 
    'Cookie': '_pxhd=4c7cs06d7c42as40601e7d338a1084ca96e4ee91dfa42bd2368e86fec4e66bcd1:e573a66d0-397x5-11ea-b7bd-97b9265412f5'}


[<Response [307]>]

<h1 class="logo">Bloomberg</h1>

1 Ответ

1 голос
/ 19 января 2020

Это Общий ответ Я написал, потому что у меня была похожая проблема, ваша проблема может быть в том, что веб-сервер просит вас добавить эти куки в ваши дальнейшие запросы. Вы установили для своих файлов cookie значение '', поэтому они удаляются, а ваши новые файлы cookie добавляются в конец заголовков в соответствии с запросом серверов.
Что если мы просто используем get ():

import requests
import logging
import http.client as http_client
http_client.HTTPConnection.debuglevel = 1

#init logging
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

requests.get("http://google.com", allow_redirects=False)

Здесь я включил ведение журнала, чтобы вы могли видеть запросы по мере их выполнения (код регистрации не показан в следующих примерах). Это приводит к выводу:

DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): google.com:80
send: b'GET / HTTP/1.1\r\nHost: google.com\r\nUser-Agent: python-requests/2.21.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n'
...

Как видите, запросы инициируют некоторые заголовки, даже когда мы этого не сказали. Что произойдет, если мы передадим ему заголовки в нужном формате?

import requests
headers = { 
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0"
}
requests.get("http://google.com", headers=headers, allow_redirects=False)

Здесь мы ожидаем, что «user-agent» будет отображаться в конце нашего запроса, однако выходные данные показывают иначе:

 DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): google.com:80
send: b'GET / HTTP/1.1\r\nHost: google.com\r\nuser-agent: Mozilla/5.0\r\naccept-encoding: gzip, deflate, br\r\naccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nConnection: keep-alive\r\naccept-language: en-US,en;q=0.9\r\nupgrade-insecure-requests: 1\r\n\r\n'
...

«User-agent» отображается в середине! Что дает? Давайте посмотрим на некоторый исходный код из библиотеки.


def __init__(self):

        #: A case-insensitive dictionary of headers to be sent on each
        #: :class:`Request <Request>` sent from this
        #: :class:`Session <Session>`.
        self.headers = default_headers()
        ...

Когда мы запускаем Session, первое, что он делает, это назначает ему заголовки по умолчанию и любые дополнительные заголовки, предоставляемые Пользователь «косвенно» (через функцию) будет добавлен к стандартному.
Это проблема, так как при добавлении двух диктов (даже OrderedDicts) результат сохраняет порядок оригинальных диктов. Мы можем видеть это в приведенном выше примере, где атрибут «user-agent» сохранил свою позицию секунды в dict .
Это код для процесса добавления, если вам интересно:

def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
    """Determines appropriate setting for a given request, taking into account
    the explicit setting on that request, and the setting in the session. If a
    setting is a dictionary, they will be merged together using `dict_class`
    """

    if session_setting is None:
        return request_setting

    if request_setting is None:
        return session_setting

    # Bypass if not a dictionary (e.g. verify)
    if not (
            isinstance(session_setting, Mapping) and
            isinstance(request_setting, Mapping)
    ):
        return request_setting

    merged_setting = dict_class(to_key_val_list(session_setting))
    merged_setting.update(to_key_val_list(request_setting))

    # Remove keys that are set to None. Extract keys first to avoid altering
    # the dictionary during iteration.
    none_keys = [k for (k, v) in merged_setting.items() if v is None]
    for key in none_keys:
        del merged_setting[key]

    return merged_setting


Так что же такое fix ?

Вам придется полностью переопределить заголовок по умолчанию. Я могу подумать, что для этого нужно использовать Session, а затем напрямую заменить заголовок:

session = requests.Session()
headers = { 
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"cookie": "Cookie: Something",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0"
}
# session.cookies.add_cookie_header(session)
session.headers = headers
a = session.get("https://google.com/", allow_redirects=False)

, которые дают желаемый результат, без необходимости каких-либо OrderedDict

DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): google.com:443
send: b'GET / HTTP/1.1\r\nHost: google.com\r\naccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\naccept-encoding: gzip, deflate, br\r\naccept-language: en-US,en;q=0.9\r\ncookie: Cookie: Something\r\nupgrade-insecure-requests: 1\r\nuser-agent: Mozilla/5.0\r\n\r\n'
...

Приведенный выше пример доказывает, что все осталось там, где и должно быть, даже если вы проверите response.request.headers все должно быть в порядке (по крайней мере, для меня это так)
PS: я не потрудился чтобы проверить, если использование OrderedDict имеет значение здесь, но если у вас все еще есть какие-либо проблемы, попробуйте использовать один вместо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...