Для языка Python существует довольно много библиотек для работы с веб-ресурсами. Это и стандартная urllib / urllib2 и сторонние -
mechanize, Twill, Request, Client Form.
В данной статье я рассмотрю работу с библиотекой mechanize, т. к. именно ее инструменты помогли мне "победить" задачу автоматизации скачивания материала с одного веб-сайта.
Суть проблемы я буду излагать достаточно пространно, т. к. не могу приводить здесь конкретный пример, но надеюсь - вам будет примерно понятно.
Проблема заключалась в следующих моментах:
- для скачивания нужно было авторизоваться на сайте. Причем, авторизация с помощью forms, а не Basic HTTP.
- необходимо было хранить кукисы, дабы авторизация не пропала.
- путем манипуляций со списками (SelectControl) выбирались параметры скачивания.
- далее нужно было получить ссылку, содержащую уникальный токен, не позволявший сачать файл по одной и той же ссылке боле 1 раза просто поменяв параметры GET запроса.
- и авторизация и скачивание и всё остальное нехорошие программисты сделали на одной html-странице в одной и той же форме, только с разными кнопками типа Submit.
Итак, начнемс. Вначале импорт необходимых библиотек. Mechanize не идет в стандартной поставке с Python и его необходимо установить или с помозью PiPy или вручную, как написано
на официальном сайте (python setup.py install).
import cookielib, shutil, os
from mechanize import Browser
Далее, создаем объекты: основной Browser и объект для хранения кукисов, который прикрепляем к нашему Browser. Объект Browser представляет собой контейнер по смыслу похожий на вкладку настоящего браузера. Т. е. в пределах его можно оществлять навигацию по web-сайту, авторизацию, хранить кукисы и т. д.
br = Browser()
# Create cookie jar and attach it to Browser
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
Затем, добавляем html хэдэры и открываем URL нужной странички в объекте Browser.
# Add some headers
br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')]
# Open url in Browser instance
br.open('http://www.example.com/download.aspx')
Далее выбираем форму, в которую будем вносить данные. nr=0 - индекс формы по счету в коде веб-страницы (0,1,2 ...) И вводим данные в поля для авторизации в формате (для элементов типа TextControl):
br["id_html_элемента"] = "Значение"
id элементов и возможные значения можно посмотреть двумя способами:
- в браузере Google Chrome нажать правой кнопкой мыши на нужном элементе и выбрать Просмотр исходного кода элемента, затем правой кнопкой на выделенном элементе и Copy as HTML. После этого, вставить текст в любой текстовый редактор.
- выполнив код в интерпретаторе python или в отдельном скрипте:
import cookielib
from mechanize import ParseResponse, urlopen
response = urlopen("http://www.eoddata.com/download.aspx")
forms = ParseResponse(response, backwards_compat=False)
form = forms[0]
print form
Вы получите список всех элементов формы и их возможных значений в формате:
<Тип(id=список_значений)>
Вроде такого:
<aspnetForm POST http://www.example.com/download.aspx application/x-www-form-urlencoded
<SelectControl(ctl00$DataFormat=[17, 2, 36, 16, 27, 28, 33, 32, 8, 24, 35, *9, 1, 39, 11, 14, 6, 5, 4, 12, 3, 26, 15])>
<SubmitControl(ctl00$Download=Download) (readonly)>
<TextControl(ctl00$txtEmail=)>
<PasswordControl(ctl00$txtPassword=)>
<CheckboxControl(ctl00$Remember=[on])>
<SubmitControl(ctl00$btnLogin=Login) (readonly)>>
Итак, пример кода основного скрипта для авторизации:
# Select form for modification and "enter" login info
br.select_form(nr=0)
br["ctl00$txtEmail"] = "User"
br["ctl00$txtPassword"] = "Secret"
# Submit form
br.submit(nr=3)
Обратите внимание на строку
br.submit(nr=3)
В скобках указан номер кноки типа Submit по порядку её нахождения в html-коде страницы. Это важно, если в форме есть несколько кнопок типа Submit, но выполняющих различные функции (как в нашем случае). Нумерация 0,1,2...
Далее, выбираем необходимые данные в списках значений, например (значения посмотреть описанными выше методами):
br.select_form(nr=0)
# Select Options
br["ctl00$cboSomething"] = ["EXAMPLE",]
br["ctl00$cboDataFormat"] = ["11",]
# Update page
br.submit(nr=1)
После этого парсим код страницы для получения ссылки на файл. В каждом конкретном случае парсинг будет, конечно же, разным - потому не привожу его здесь.
Скачиваем файл (считая, что искомый URL на файл находится в переменной download_url):
local_path = "/home/user"
filename = "very_important.txt"
f = br.retrieve(download_url)[0]
# Copy saved file to normal location
shutil.copy2(f,os.path.join(local_path, filename))
В переменной f мы получаем путь к скачанному файлу, обычно это какое-то случайное имя в директории /tmp. Далее перемещаем его в нужное нам место.
Ссылки:
- http://stockrt.github.io/p/emulating-a-browser-in-python-with-mechanize/
- http://www.voidspace.org.uk/python/articles/authentication.shtml
- http://mozgovipc.blogspot.com/2012/06/python-http-basic-authentication-with.html
- http://docs.python-requests.org/en/latest/
- http://stackoverflow.com/questions/9541677/urllib2-post-request
- http://docs.python.org/2/howto/urllib2.html
- http://stackoverflow.com/questions/9288662/need-more-mechanize-documentation-python
- http://www.pythonforbeginners.com/cheatsheet/python-mechanize-cheat-sheet
- http://blog.spritecloud.com/2010/01/posting-forms-with-python/