Как получить данные с веб-страницы, которая не отвечает на GET

Я новичок в программировании и учусь парсить веб-страницы. Мой текущий проект — собирать цены на топливо в супермаркетах. Данные доступны здесь . Поскольку очистка Python не удалась при попытке получить данные с этой страницы. Я пытался выполнить отладку с помощью Curl, и кажется, что сервер блокирует входящие запросы на очистку. Есть ли другой способ получить необходимую информацию?

⏺ ~ > curl -v "https://www.tesco.com/fuel_prices/fuel_prices_data.json" --http1.1
*   Trying 96.16.109.100:443...
* Connected to www.tesco.com (96.16.109.100) port 443
* ALPN: curl offers http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: C=GB; L=Welwyn Garden City; jurisdictionCountryName=GB; O=Tesco PLC; businessCategory=Private Organization; serialNumber=00445790; CN=www.tesco.com
*  start date: Mar 20 13:08:28 2024 GMT
*  expire date: Apr 20 13:08:27 2025 GMT
*  subjectAltName: host "www.tesco.com" matched cert's "www.tesco.com"
*  issuer: C=US; O=Entrust, Inc.; OU=See www.entrust.net/legal-terms; OU=(c) 2014 Entrust, Inc. - for authorized use only; CN=Entrust Certification Authority - L1M
*  SSL certificate verify ok.
* using HTTP/1.1
> GET /fuel_prices/fuel_prices_data.json HTTP/1.1
> Host: www.tesco.com
> User-Agent: curl/8.4.0
> Accept: */*

* Recv failure: Connection reset by peer
* LibreSSL SSL_read: LibreSSL/3.3.6: error:02FFF036:system library:func(4095):Connection reset by peer, errno 54
* Closing connection
* Send failure: Broken pipe
* Send failure: Broken pipe
curl: (56) Recv failure: Connection reset by peer

Обновлено: код py для удаления

import requests

URL = "https://www.tesco.com/fuel_prices/fuel_prices_data.json"

page = requests.get(URL)

print(page.text)

Результат:

Traceback (most recent call last):
  File "/Users/abjohnson/coding/pylab/beautiful_web_scraper.py", line 6, in <module>
    page = requests.get(URL)
  File "/Users/abjohnson/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
  File "/Users/abjohnson/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Users/abjohnson/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
  File "/Users/abjohnson/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "/Users/abjohnson/Library/Python/3.9/lib/python/site-packages/requests/adapters.py", line 501, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', TimeoutError(60, 'Operation timed out'))

Интересный. Отлично работает с HTTPie. Либо это какая-то тонкая ошибка во взаимодействии клиент-сервер, либо они специально блокируют завиток.

deceze 01.05.2024 12:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
86
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Похоже, сервер выполняет фильтрацию на основе заголовка User-Agent в вашем запросе.

import requests

headers = {
    'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/'
      '537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36Edg/123.0.0.0')
}

sess = requests.Session()
sess.headers.update(headers)
u = "https://www.tesco.com/fuel_prices/fuel_prices_data.json"
sess.get(u)
# returns:
<Response [200]>

Спасибо за решение. Какие заголовки используются в запросах Python без указания каких-либо символов? потому что я не думал выбирать заголовки (и не знаю, что они делают) из вывода Curl

j4son 01.05.2024 13:36

пользовательский агент по умолчанию — 'python-requests/2.31.0' для запросов версии 2.31.0.

James 01.05.2024 14:55

спасибо за ваше решение. Узнал что-то новое :)

j4son 01.05.2024 15:15

@James Вы правы: в запросах есть пользовательский агент по умолчанию. К сожалению, не все веб-сайты его принимают, поэтому лучше использовать что-то, что действительно отражает то, что может использовать современный браузер.

SIGHUP 01.05.2024 15:20

Пока вы предоставляете приемлемые запросы User-Agent, вы можете справиться с этим:

import requests

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15"
}
url = "https://www.tesco.com/fuel_prices/fuel_prices_data.json"

with requests.get(url, headers=headers) as response:
    response.raise_for_status()
    print(response.json())

Выход:

Не показано из-за размера, но при тестировании была получена ожидаемая структура JSON.

Спасибо. Есть ли способ узнать, какие заголовки пользовательского агента ожидает сервер?

j4son 01.05.2024 14:41

Вероятно, он пытается проанализировать пользовательский агент, который имеет довольно стандартный формат. если это не удается, он возвращает код ошибки.

James 01.05.2024 14:56

@j4son Я так не думаю. Просто используйте все, что будет отправлено из известного браузера. Я не знаю, поддерживается ли эта в актуальном состоянии, но она может оказаться вам полезной.

SIGHUP 01.05.2024 15:00

@SIGHUP, спасибо за решение. Жаль, что STACK позволяет мне выбрать только один ответ.

j4son 01.05.2024 15:14

Другие вопросы по теме