Я новичок в программировании и учусь парсить веб-страницы. Мой текущий проект — собирать цены на топливо в супермаркетах. Данные доступны здесь . Поскольку очистка 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'))
Похоже, сервер выполняет фильтрацию на основе заголовка 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
пользовательский агент по умолчанию — 'python-requests/2.31.0'
для запросов версии 2.31.0.
спасибо за ваше решение. Узнал что-то новое :)
@James Вы правы: в запросах есть пользовательский агент по умолчанию. К сожалению, не все веб-сайты его принимают, поэтому лучше использовать что-то, что действительно отражает то, что может использовать современный браузер.
Пока вы предоставляете приемлемые запросы 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 Я так не думаю. Просто используйте все, что будет отправлено из известного браузера. Я не знаю, поддерживается ли эта в актуальном состоянии, но она может оказаться вам полезной.
@SIGHUP, спасибо за решение. Жаль, что STACK позволяет мне выбрать только один ответ.
Интересный. Отлично работает с HTTPie. Либо это какая-то тонкая ошибка во взаимодействии клиент-сервер, либо они специально блокируют завиток.