среда, 18 июня 2014 г.

Использование urllib2 в Python

Описание


Это статья является введением в работу с urllib2 в Python. В ней, мы сосредоточимся на работу с URL адресом, GET и POST запросами, изменением User Agent, а так же обработке ошибок.

Прошу заметить, что это статья написана для Python 2.x.

Что такое urllib2?


urllib2 это модуль Python, который призван на нашу землю, чтобы помочь работать с URL-адресом.
Модуль имеет свои функции и классы, которые помогают в работе с URL - basic и digest аутентификации, перенаправлениях, cookie и многое другое.

Магия начинается тогда, когда вы импортируете модуль urllib2 в свой скрипт...


Чем urllib отличается от urllib2?


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

urllib2 в качестве аргумента может принимать Request object, чтобы добавлять заголовки к запросу и другое, в то время как urllib может принимать только стринговый URL. 

urllib имеет метод urlencode, который используется для кодирования строки в вид, удовлетворяющий правилам данных в запросах, а urllib2 не имеет такой функции. Из-за этого urllib и urllib2 часто используются вместе.

Обо всем этом, и даже большем, Вы можете прочесть в официальной документации:
  1. urllib
  2. urllib2

Метод urlopen


urllib2 предлагает очень простой интерфейс, в виде urlopen функции.
Эта функция способна извлечь URL-адрес с помощью различных протоколов (HTTP, FTP, ...)
Просто передайте URL адрес функции urlopen(), чтобы получить доступ к удаленным данным.

Кроме того, urllib2 предлагает интерфейс обработки распространенных ситуаций -
таких как basic-аутентификация, cookies, прокси-серверы и так далее. Но обо всем, по порядку.

GET запрос к URL


Это наиболее распространенный способ использования библиотеки. Ниже, Вы можете увидеть, как сделать простой запрос с помощью urllib2.

  1. Для начала, импортируем urllib2 модуль.
  2. Положим ответ сервера в переменную, например response. (response является file-like объектом.)
  3. Теперь читаем данные из response в строковую переменную html
  4. В дальнейшем, проводим какие-либо действие с переменной html.

Примечание: если существует пробел в адресе, необходимо проенкодить его, используя метод urlencode.

А, теперь, давайте рассмотрим несколько примеров, демонстрирующих возможности библиотеки urllib2.

import urllib2

response = urllib2.urlopen('http://python.org/')
print response.info()
html = response.read()
# делаем что-нибудь
response.close()

# Заметка: также можно использовать URL начинающиеся с "ftp:", "file:", и т.д.

Пример #2
import urllib2

response = urllib2.urlopen('http://python.org/')
print "Ответ (file-like object):", response

# URL из запроса
print "The URL is: ", response.geturl()

# Ответ сервера
print "This gets the code: ", response.code

# Заголовки ответа в виде словаря
print "The Headers are: ", response.info()

# Достаем дату сервера из заголовков ответа
print "The Date is: ", response.info()['date']

# Получаем заголовок 'server' из заголовков 
print "The Server is: ", response.info()['server']

# Получаем весь html страницы
html = response.read()
print "Get all data: ", html

# Узнаем длину страницу
print "Get the length :", len(html)

for line in response:
 print line.rstrip()


Скачивание файла с помощью urllib2


import urllib2

# файл для записи
file = "downloaded_file.html"

url = "http://www.pythonforbeginners.com/"
response = urllib2.urlopen(url)

# откроем файл на запись
fh = open(file, "w")

# читаем URL и записываем в локальный файл
fh.write(response.read())
fh.close()

# аналогичный вариант
with open(file, 'w') as f: f.write(response.read())

А теперь пример с скачиванием бинарного файла:

import urllib2

mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")

output = open('test.mp3','wb')
output.write(mp3file.read())
output.close()

urllib2 Request


Если нужно отправить что-то замысловатое, например добавить дополнительные заголовки к запросу, то нужно использовать urllib2.Request.

Вы можете задать исходящие данные в Request, которые хотите отправить на сервере.
Кроме того, вы можете передавать на сервер дополнительную информацию (метаданные) о данных, отправляемых на сервер или о самом запросе, эта информация передается в виде HTTP заголовков.

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


# Данные, которые хотим отправить
query_args = { 'q':'query string', 'foo':'bar' }

# Производим urlencodes для ранее созданного словаря (вот для чего мы импортировали библиотеку urllib вверху)
data = urllib.urlencode(query_args)

# Отправляем HTTP POST запрос
request = urllib2.Request(url, data)

response = urllib2.urlopen(request)
 
html = response.read()

# Выводим результат
print html


User Agent


Чтобы идентифицировать клиента, который отправляет запрос, будь то браузер или какая-либо программа, умные люди придумали заголовок User-Agent. Который хранит в себе название и версию клиента.
По умолчанию urllib2 идентифицирует себя как Python-urllib/x.y
где x и y - это номера версий Python-релиза.

С urllib2 можно добавить собственные заголовки к запросу.
Причина, по которой нужно изменять User Agent бывают разные, но в большинстве случаев это делается для того, чтобы как можно больше, походить на реального человека, а не скрипт.

При создании Request объекта нужно добавить заголовки в словарь,
для этого используйте опцию add_header().



import urllib2

# наш URL
url = 'http://www.google.com/#q=my_search'

# Добавляем заголовок. 
headers = {'User-Agent' : 'Mozilla 5.10'}
# создаем Request объект. 
request = urllib2.Request(url, None, headers)

# или так
# request.add_header('User-Agent' : 'Mozilla 5.10')

# Посылаем запрос и получаем ответ
response = urllib2.urlopen(request)

# Выводим заголовки
print response.headers

urllib.urlparse


urlparse модуль содержит функции для анализа URL строки.

Он определяет стандартный интерфейс разделения Uniform Resource Locator (URL)
строки в несколько дополнительных частей, называемых компонентами (scheme, location, path, query и fragment).

Скажем, у вас есть URL:
http://www.python.org:80/index.html
 в нем, будут следующие компоненты:

  1. schema: http
  2. location: www.python.org:80
  3. path: index.html
query и fragment будут пустыми.

import urlparse

url = "http://python.org"
domain = urlparse.urlsplit(url)[1].split(':')[0]

print "The domain name of the url is: ", domain

более подробно о urlparse, вы можете почитать в официальной документации.

urllib.urlencode


Когда вы передаете информацию через URL, вы должны убедиться, что в ней используется только определенные, разрешенные символы.

Разрешенные символы - это любые алфавитные символы, цифры и некоторые специальные
символы, которые имеют значение в строке URL-адреса.

Наиболее часто кодируются символ "пробел". Вы видите этот символ каждый раз, когда вы видите знак "плюс " (+) в URL. Это означает пробел.
Знак "плюс" выступает как специальный символ, представляющий пробелы в URL

Аргументы могут быть переданы на сервер при их кодировании и последующему добавлению к URL-адресу.


import urllib

query_args = { "q":"query string", "sql":"' or 1='1" }
encoded_args = urllib.urlencode(query_args)

print 'Encoded:', encoded_args


В результате получим следующее:
Encoded: q=query+string&sql=%27+or+1%3D%271
пробел преобразовался в символ +, одинарная кавычка в %27.

Python urlencode принимает пару переменная/значение и создает уже кодированную строку.

from urllib import urlencode

artist = "Kruder & Dorfmeister"
artist = urlencode({'ArtistSearch':artist})

Результатом будет:
ArtistSearch=Kruder+%26+Dorfmeister

Обработка ошибок

 

Этот раздел основывается на информации, полученной из voidspace.org.uk в отличной статье:
"urllib2 - The Missing Manual"

urlopen поднимает URLError, когда он не может обработать ответ сервера. HTTPError является подклассом URLError, и поднимается в конкретном случае - при обработке ошибки, связанной с HTTP.

URLError


Часто, URLError вызывается, потому что нет сетевого соединения или указанный сервер не существует.
В этом случае нам нужен атрибут 'reason', который содержит код и текст сообщения об ошибке. 

import  urllib2

request = urllib2.Request('http://www.pretend_server.org')
try: 
    urllib2.urlopen(request)
except urllib2.URLError, e:
    print e.reason


HTTPError


Каждый HTTP-ответ от сервера содержит код состояния. Иногда этот код указывает, что сервер не в состоянии обработать запрос.

Обработчик по умолчанию будет обрабатывать некоторые из этих кодов для вас (например,
если ответ "перенаправление", urllib2 обработает это).
При тех случаях, которые библиотека не может обработать ошибку, urlopen вызывает HTTPError.

from urllib2 import Request, urlopen, URLError

req = Request('http://ya.ru/error.html')

try:
    response = urlopen(req)

except URLError, e:

    if hasattr(e, 'reason'):
        print 'We failed to reach a server.'
        print 'Reason: ', e.reason

    elif hasattr(e, 'code'):
        print 'The server couldn\'t fulfill the request.'
        print 'Error code: ', e.code
else:
    print 'no error'

Ссылки по теме:

  1. http://pymotw.com/2/urllib2/
  2. http://www.kentsjohnson.com/
  3. http://www.voidspace.org.uk/python/articles/urllib2.shtml
  4. http://techmalt.com/
  5. http://www.hacksparrow.com/
  6. http://docs.python.org/2/howto/urllib2.html
  7. http://stackoverflow.com/
  8. http://www.oreillynet.com/


Выбираем самые популярные страницы из apache лога.

лог-файл Apache в большинстве случаем, представляется огромным и трудно-читаемым файлом с огромным количеством записей.
Сейчас, я покажу тебе как можно вычислить самые популярные страницы на твоем сайте используя лог файл.

В этом примере, мы узнаём популярные URL-адреса из GET запросов. Для этого будем использовать функцию counter, которая присутствует в модуле Python Collections.
import collections

logfile = open("yourlogfile.log", "r")

clean_log=[]

for line in logfile:
    try:
        # копируем URL адреса в пустой список.
        # Берем все символы между 'GET' и 'HTTP'
        clean_log.append(line[line.index("GET")+4:line.index("HTTP")])
    except:
        pass

counter = collections.Counter(clean_log)

# get the Top 50 most popular URLs
for count in counter.most_common(50):
    print(str(count[1]) + "\t" + str(count[0]))

logfile.close()

вторник, 17 июня 2014 г.

Использование рандом модуля в Python

randint

#Генерирует целое число между 1 и 10. Первое значение должно быть меньше второго.
random.randint(1, 10)

randrange

#Генерация случайно выбранного элемента из диапазона(начало, конец, шаг)
random.randrange(start, stop[, step])

choice

#Выбирает случайное значение из последовательности
random.choice( ['red', 'black', 'green'] ).

shuffle

#Перемешивает элементы списка
random.shuffle(list)

Достаем доменное имя из URL

Это простой скрипт, достающий имя домена из URL.


import urlparse
url = "http://python.org"
domain = urlparse.urlsplit(url)[1]
print "The domain name of the url is: ", domain


Давай разберем пример по-подробнее.
Команда urlparse.urlsplit(url) в данном примере вернет список:
SplitResult(scheme='http', netloc='python.org', path='', query='', fragment='')
на первом, нулевом месте, будет стоять протокол, а на первом само доменное имя, которое нам и требуется. 

Python код: собрать все ссылки с сайта

Описание

В этом примере мы будем использовать модуль re, для того чтобы получить все ссылки с любого веб-сайта. 
Один из самых мощных функций в re модуле является re.findall()
В то время как re.search() используется, чтобы найти первое вхождение удовлетворяющее шаблону, re.findall() находит все вхождения и возвращает их в виде списка строк.

Собираем все ссылки с веб-сайта

Этот пример будет получить все ссылки из любого HTML кода. 
Чтобы найти их, мы в этом примере будем использовать модуль urllib2 вместе 
с re.module.


import urllib2
import re

#производим соединение с URL
website = urllib2.urlopen(url)

#читаем html код
html = website.read()

#используем re.findall для парсинга всех ссылок с сайта
links = re.findall('"((http|ftp)s?://.*?)"', html)

print links

urllib2 - https://docs.python.org/2/library/urllib2.html
re       - https://docs.python.org/2/library/re.html

Изменение User Agent в Python

Стандартно, python-скрипт при http(s) запросе, будет отсылать заголовок User Agent с значением "Python-urllib/2(3).x".

Если Вам требуется изменить этот заголовок, тогда опирайтесь на простой пример:

import urllib2

request = urllib2.Request('http://127.0.0.1/')
request.add_header('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1') 
res = urllib2.urlopen(request)
html = res.read()

urllib2 - https://docs.python.org/2/library/urllib2.html