[Борьба за разработку поискового робота Python3] 3-Использование базовых библиотек 1.1-Отправить запрос

задняя часть Python рептилия модульный тест
[Борьба за разработку поискового робота Python3] 3-Использование базовых библиотек 1.1-Отправить запрос

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

1. urlopen()

urllib.requestМодуль предоставляет самый базовый метод построения HTTP-запросов, который можно использовать для имитации процесса инициации запроса браузера, а также обрабатывает проверку авторизации (аутентификацию), перенаправление (перенаправление), файлы cookie браузера и другой контент.

Давайте посмотрим на его сильные стороны. Возьмем в качестве примера официальный сайт Python, давайте возьмем эту страницу:

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(response.read().decode('utf-8'))

Результат работы показан на рис. 3-1.

Рисунок 3-1 Результат работы

Здесь мы используем только две строки кода для завершения сканирования официального сайта Python и вывода исходного кода веб-страницы. После получения исходного кода? Можем ли мы извлечь все нужные ссылки, адреса изображений и текстовую информацию?

Далее посмотрите, что именно он возвращает. использоватьtype()Метод выводит тип ответа:

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(type(response))

Результат выглядит следующим образом:

<class 'http.client.HTTPResponse'>

Можно обнаружить, что этоHTTPResposneтип объекта. В основном содержитread(),readinto(),getheader(name),getheaders(),fileno()и другие методы, а такжеmsg,version,status,reason,debuglevel,closedи другие свойства.

Получив этот объект, мы назначаем его какresponseпеременные, а затем вы можете вызвать эти методы и свойства, чтобы получить ряд сведений о возвращаемом результате.

Например, вызовread()Метод может получить возвращенное содержимое веб-страницы, вызватьstatusАтрибут может получить код состояния возвращаемого результата, например, 200 для успешного запроса, 404 для веб-страницы, не найденной и т. д.

Давайте посмотрим на другой пример:

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))

Результаты приведены ниже:

200
[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('X-Clacks-Overhead', 'GNU Terry Pratchett'), ('Content-Length', '47397'), ('Accept-Ranges', 'bytes'), ('Date', 'Mon, 01 Aug 2016 09:57:31 GMT'), ('Via', '1.1 varnish'), ('Age', '2473'), ('Connection', 'close'), ('X-Served-By', 'cache-lcy1125-LCY'), ('X-Cache', 'HIT'), ('X-Cache-Hits', '23'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]
nginx

Видно, что первые два вывода выводят код состояния ответа и информацию заголовка ответа соответственно, а последний вывод вызывается вызовомgetheader()метод и передать параметрServerполучить заголовок ответаServerзначение, результатnginx, что означает, что сервер построен на Nginx.

Используйте самые основныеurlopen()метод, который может выполнить самый простой и простой обход веб-страницы по запросу GET.

Если вы хотите передать в ссылку какие-то параметры, как это сделать? Первый взглядurlopen()API функции:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

Можно обнаружить, что в дополнение к первому параметру мы можем передать URL-адрес, мы также можем передать другой контент, напримерdata(Дополнительная информация),timeout(таймаут) и т.д.

Ниже мы подробно опишем использование этих параметров.

параметр данных

dataПараметры являются необязательными. Если вы хотите добавить этот параметр, и если он содержится в формате кодированного потока байтов, т.е.bytesтип, вам нужно пройтиbytes()преобразование метода. Кроме того, если этот параметр передается, его метод запроса больше не является методом GET, а методом POST.

Давайте рассмотрим пример:

import urllib.parse
import urllib.request

data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())

Здесь мы передаем параметрword, значениеhello. его нужно перекодировать вbytes(поток байтов) тип. Среди них поток байтов принимаетbytes()метод, первый параметр метода должен бытьstr(строка), вам нужно использоватьurllib.parseв модулеurlencode()метод для преобразования словаря параметров в строку; второй параметр указывает формат кодировки, который указан здесь какutf8.

Запрошенный здесь сайтhttpbin.org, который может обеспечить тестирование HTTP-запросов. URL-адрес, который мы запрашиваем на этот раз,httpbin.org/post, эту ссылку можно использовать для проверки POST-запроса, она может выводить некоторую информацию о запросе, который содержит переданную нами информациюdataпараметр.

Результаты приведены ниже:

{
     "args": {},
     "data": "",
     "files": {},
     "form": {
         "word": "hello"
     },
     "headers": {
         "Accept-Encoding": "identity",
         "Content-Length": "10",
         "Content-Type": "application/x-www-form-urlencoded",
         "Host": "httpbin.org",
         "User-Agent": "Python-urllib/3.5"
     },
     "json": null,
     "origin": "123.124.23.253",
     "url": "http://httpbin.org/post"
}

Переданные нами параметры появляются вformВ поле это указывает, что он имитирует метод отправки формы и передает данные в режиме POST.

параметр тайм-аута

timeoutПараметр используется для установки времени ожидания в секундах, что означает, что если запрос превышает установленное время и не получил ответа, будет выдано исключение. Если этот параметр не указан, будет использоваться глобальное время по умолчанию. Он поддерживает HTTP, HTTPS, FTP-запросы.

Давайте рассмотрим пример:

import urllib.request

response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
print(response.read())

Результаты приведены ниже:

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/var/py/python/urllibtest.py", line 4, in <module> response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
...
urllib.error.URLError: <urlopen error timed out>

Здесь мы устанавливаем тайм-аут на 1 секунду. Через 1 секунду программы сервер так и не ответил, поэтому кинулURLErrorаномальный. Исключение принадлежитurllib.errorмодуль, причина ошибки - тайм-аут.

Поэтому, установив этот тайм-аут, вы можете управлять веб-страницей, чтобы пропустить ее сканирование, если она не отвечает в течение длительного времени. Это можно использоватьtry exceptзаявление для достижения, соответствующий код выглядит следующим образом:

import socket
import urllib.request
import urllib.error

try:
    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

Здесь мы спрашиваемhttpbin.org/getПротестируйте ссылку, установите тайм-аут на 0,1 секунды, затем захватитеURLErrorИсключение, тогда судите об исключенииsocket.timeoutВведите (имеется в виду исключение тайм-аута), чтобы это действительно была ошибка из-за тайм-аута, а распечаткаTIME OUT.

Результаты приведены ниже:

TIME OUT

Согласно здравому смыслу получить ответ сервера в течение 0,1 секунды в принципе невозможно, поэтому выводTIME OUTнамекать.

установивtimeoutЭтот параметр используется для реализации обработки времени ожидания, что иногда полезно.

Другие параметры

Кромеdataпараметры иtimeoutКроме параметров естьcontextпараметр, он должен бытьssl.SSLContextВведите, чтобы указать настройки SSL.

также,cafileа такжеcapathЭти два параметра определяют сертификат ЦС и его путь соответственно, что полезно при запросе ссылок HTTPS.

cadefaultПараметр устарел, и его значение по умолчанию равноFalse.

объяснил ранееurlopen()Использование метода, с помощью этого самого основного метода мы можем выполнять простые запросы и веб-скраппинг. Более подробную информацию можно найти в официальной документации:docs.Python.org/3/library/U….

2. Request

мы знаем, используяurlopen()Метод может инициировать самый простой запрос, но этих простых параметров недостаточно для построения полного запроса. Если вам нужно добавить в запрос заголовки и другую информацию, вы можете использовать более мощныйRequestкласс для сборки.

Во-первых, давайте почувствуем это на примереRequestПрименение:

import urllib.request

request = urllib.request.Request('https://python.org')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

Можно обнаружить, что мы все еще используемurlopen()метод для отправки этого запроса, но на этот раз параметром метода является уже не URL, аRequestтип объекта. Построив эту структуру данных, мы, с одной стороны, можем отделить запрос в объект, а с другой стороны, можем более обильно и гибко настраивать параметры.

Давайте взглянемRequestКакие параметры можно использовать для построения, метод его построения выглядит следующим образом:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
  • первый параметрurlИспользуется для запроса URL, это обязательный параметр, остальные параметры необязательны.
  • второй параметрdataЕсли вы хотите пройти его, вы должны пройти егоbytes(поток байтов) тип. Если это словарь, вы можете сначала использоватьurllib.parseв модулеurlencode()кодирование.
  • третий параметрheadersэто словарь, это заголовок запроса, мы можем передать его при построении запросаheadersПараметры создаются напрямую или путем вызова экземпляра запроса.add_header()добавлен метод. Чаще всего для добавления заголовков запросов используется изменениеUser-Agentчтобы скрыть браузер, по умолчаниюUser-Agentявляется Python-urllib, мы можем замаскировать браузер, изменив его. Например, чтобы замаскировать Firefox, вы можете установить его на:

Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11

  • четвертый параметрorigin_req_hostОтносится к имени хоста или IP-адресу запрашивающей стороны.
  • пятый параметрunverifiableУказывает, является ли запрос непроверяемым, по умолчаниюFalse, что означает, что у пользователя недостаточно прав для выбора получения результатов этого запроса. Например, мы запрашиваем изображение в HTML-документе, но у нас нет разрешения на автоматическое получение изображения, которое затем невозможно проверить.的值就是Правда`.
  • шестой параметрmethodСтрока, указывающая метод, используемый запросом, например GET, POST и PUT.

Давайте посмотрим на запрос построения, передав несколько параметров:

from urllib import request, parse

url = 'http://httpbin.org/post'
headers = {
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
    'Host': 'httpbin.org'
}
dict = {
    'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

Здесь мы создаем запрос с 4 параметрами, гдеurlто есть URL-адрес запроса,headersуказано вUser-Agentа такжеHost,параметрdataиспользоватьurlencode()а такжеbytes()метод преобразования в поток байтов. Кроме того, метод запроса указан как POST.

Результаты приведены ниже:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "Germey"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Content-Length": "11", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)"
  }, 
  "json": null, 
  "origin": "219.224.169.11", 
  "url": "http://httpbin.org/post"
}

По результатам наблюдения можно обнаружить, что мы успешно установилиdata,headersа такжеmethod.

Кроме того,headersтакже можно использоватьadd_header()метод добавления:

req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')

Таким образом, мы можем более удобно построить запрос и реализовать отправку запроса.

3. Расширенное использование

В приведенном выше процессе, хотя мы можем создать запрос, что мы должны сделать для некоторых более сложных операций (таких как обработка файлов cookie, настройка прокси-сервера и т. д.)?

Затем необходим более мощный инструмент Handler. Короче говоря, мы можем понимать это как различные процессоры, некоторые из которых специализируются на проверке входа в систему, некоторые имеют дело с файлами cookie, а некоторые — с настройками прокси. Используя их, мы можем делать почти все в HTTP-запросе.

Во-первых, позвольте мне представитьurllib.requestв модулеBaseHandlerкласс, это все другоеHandler, который предоставляет самые основные методы, такие какdefault_open(),protocol_request()Ждать.

Далее идут различныеHandlerподклассы наследуют этоBaseHandlerкласс например.

  • HTTPDefaultErrorHandler: используется для обработки ошибок ответа HTTP, будут выдаваться ошибкиHTTPErrorтип исключения.
  • HTTPRedirectHandler: Используется для обработки перенаправлений.
  • HTTPCookieProcessor: используется для обработки файлов cookie.
  • ProxyHandler: Используется для установки прокси, прокси по умолчанию пуст.
  • HTTPPasswordMgr: используется для управления паролями, поддерживает таблицу имен пользователей и паролей.
  • HTTPBasicAuthHandler: используется для управления аутентификацией и может использоваться для решения проблем с аутентификацией, если аутентификация требуется при открытии ссылки.

Кроме того, существуют другиеHandlerКлассы здесь не указаны, подробности можно найти в официальной документации:docs.Python.org/3/library/U….

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

Другим важным классом являетсяOpenerDirector, мы можем назвать этоOpener. мы использовали его раньшеurlopen()Этот метод, на самом деле, предоставлен нам urllib.Opener.

Так зачем вводитьOpenerШерстяная ткань? Потому что нужно реализовать более продвинутые функции. бывшего употребленияRequestа такжеurlopen()Это эквивалентно библиотеке классов, которая инкапсулирует наиболее часто используемые для вас методы запросов, и вы можете использовать их для выполнения базовых запросов, но теперь это другое, нам нужно реализовать более продвинутые функции, поэтому нам нужно углубиться в конфигурации и использовать экземпляры более низкого уровня для завершения операции, поэтому он используется здесьOpener.

Openerможно использоватьopen()метод, тип возвращаемого значения иurlopen()такой же. Тогда это иHandlerЧто это значит? Короче говоря, используяHandlerстроитьOpener.

Вот несколько примеров, чтобы увидеть, как они используются.

проверять

При открытии некоторых веб-сайтов появляется всплывающее окно с запросом на ввод имени пользователя и пароля, и страницу можно просмотреть только после успешной проверки, как показано на рис. 3-2.

Рисунок 3-2 Страница проверки

Итак, что, если вы хотите запросить такую ​​страницу? с помощьюHTTPBasicAuthHandlerЕго можно завершить, соответствующий код выглядит следующим образом:

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = 'username'
password = 'password'
url = 'http://localhost:5000/'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
    print(html)
except URLError as e:
    print(e.reason)

Первый экземпляр здесьHTTPBasicAuthHandlerобъект, аргумент которогоHTTPPasswordMgrWithDefaultRealmобъект, который используетadd_password()Добавьте имя пользователя и пароль, которые создают процесс аутентификации.Handler.

Далее используйте этоHandlerи использоватьbuild_opener()способ построитьOpener,этоOpenerОтправка запроса означает, что проверка прошла успешно.

Далее используйтеOpenerизopen()Метод открывает ссылку, и проверка может быть завершена. Полученный здесь результат является проверенным исходным контентом страницы.

играет роль

При выполнении краулера использование прокси неизбежно, если вы хотите добавить прокси, вы можете сделать это:

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = build_opener(proxy_handler)
try:
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

Здесь мы настраиваем прокси локально, который работает на порту 9743.

используется здесьProxyHandler, параметр которого — словарь, имя ключа — тип протокола (например, HTTP или HTTPS и т. д.), значение ключа — ссылка на прокси, и можно добавить несколько прокси.

Затем используйте этот обработчик иbuild_opener()метод построенияOpener, а затем отправить запрос.

Cookies

Обработка файлов cookie требует соответствующихHandler.

Давайте используем пример, чтобы увидеть, как получить файлы cookie веб-сайта. Соответствующий код выглядит следующим образом:

import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
    print(item.name+"="+item.value)

Во-первых, мы должны объявитьCookieJarобъект. Далее необходимо использоватьHTTPCookieProcessorпостроитьHandler, и, наконец, используйтеbuild_opener()метод строитOpener,воплощать в жизньopen()функция.

Результаты приведены ниже:

BAIDUID=2E65A683F8A8BA3DF521469DF8EFF1E1:FG=1
BIDUPSID=2E65A683F8A8BA3DF521469DF8EFF1E1
H_PS_PSSID=20987_1421_18282_17949_21122_17001_21227_21189_21161_20927
PSTM=1474900615
BDSVRTM=0
BD_HOME=0

Как видите, здесь выводятся имя и значение каждого файла cookie.

Но поскольку его можно вывести, можно ли его вывести в формате файла? Мы знаем, что файлы cookie на самом деле хранятся в текстовом виде.

Ответ, конечно, да, вот посмотрите на следующие примеры:

filename = 'cookies.txt'
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)

В настоящее времяCookieJarнеобходимо заменить наMozillaCookieJar, который используется при создании файла,CookieJarПодкласс , который можно использовать для обработки файлов cookie и событий, связанных с файлами, таких как чтение и сохранение файлов cookie, а также сохранение файлов cookie в формате файлов cookie браузера типа Mozilla.

После запуска вы можете обнаружить, что создается файл cookies.txt со следующим содержимым:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file!  Do not edit.

.baidu.com    TRUE    /    FALSE    3622386254    BAIDUID    05AE39B5F56C1DEC474325CDA522D44F:FG=1
.baidu.com    TRUE    /    FALSE    3622386254    BIDUPSID    05AE39B5F56C1DEC474325CDA522D44F
.baidu.com    TRUE    /    FALSE        H_PS_PSSID    19638_1453_17710_18240_21091_18560_17001_21191_21161
.baidu.com    TRUE    /    FALSE    3622386254    PSTM    1474902606
www.baidu.com    FALSE    /    FALSE        BDSVRTM    0
www.baidu.com    FALSE    /    FALSE        BD_HOME    0

Кроме того,LWPCookieJarФайлы cookie также можно читать и сохранять, но в том же формате, что иMozillaCookieJarНе то же самое, он будет сохранен как файл cookie в формате libwww-perl (LWP).

Чтобы сохранить файл cookie в формате LWP, вы можете изменить его на:

cookie = http.cookiejar.LWPCookieJar(filename)

Контент, сгенерированный в это время, выглядит следующим образом:

#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="0CE9C56F598E69DB375B7C294AE5C591:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BIDUPSID=0CE9C56F598E69DB375B7C294AE5C591; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: H_PS_PSSID=20048_1448_18240_17944_21089_21192_21161_20929; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1474902671; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0

С этой точки зрения сгенерированный формат все же сильно отличается.

Затем, после создания файла Cookies, как читать и использовать его из файла?

Ниже мы используемLWPCookieJarВзгляните на формат в качестве примера:

cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))

Как видите, звонок здесьload()метод для чтения локального файла Cookies и получения содержимого Cookies. Но предпосылка заключается в том, что мы сначала создаем файлы cookie в формате LWPCookieJar, сохраняем их как файлы, а затем читаем файлы cookie и используем тот же метод для создания обработчика и открывателя для завершения операции.

Если текущий результат нормальный, будет выведен исходный код веб-страницы Baidu.

С помощью вышеуказанного метода мы можем реализовать настройки большинства функций запроса.

Это библиотека urllibrequestОсновное использование модуля, если вы хотите получить больше функций, вы можете обратиться к официальной документации:docs.Python.org/3/library/U….


Этот ресурс был впервые опубликован в личном блоге Цуй Цинцай Цзин Ми:Практическое руководство по разработке веб-краулера на Python3 | Цзин Ми

Если вы хотите узнать больше информации о поисковых роботах, обратите внимание на мой личный публичный аккаунт WeChat: Coder of Attack.

WeChat.QQ.com/Day/5 Это радость VE Z…(автоматическое распознавание QR-кода)