Как отправить запрос на страницу.aspx в Python
Мне нужно почистить результаты запроса с веб-страницы.aspx.
http://legistar.council.nyc.gov/Legislation.aspx
URL-адрес является статическим, так как я могу отправить запрос на эту страницу и получить результаты? Предположим, нам нужно выбрать "все годы" и "все типы" из соответствующих выпадающих меню.
Кто-то должен знать, как это сделать.
5 ответов
В качестве обзора вам нужно будет выполнить четыре основные задачи:
- отправить запрос (ы) на веб-сайт,
- получить ответ (ы) с сайта
- разобрать эти ответы
- иметь некоторую логику для итерации в вышеуказанных задачах с параметрами, связанными с навигацией (для "следующих" страниц в списке результатов)
Обработка запросов и ответов http выполняется с помощью методов и классов из стандартных библиотек Python urllib и urllib2. Разбор html-страниц может быть выполнен с помощью HTMLParser стандартной библиотеки Python или с другими модулями, такими как Beautiful Soup
Следующий фрагмент демонстрирует запрос и получение запроса на сайте, указанном в вопросе. Этот сайт управляется ASP, и в результате нам необходимо убедиться, что мы отправляем несколько полей формы, некоторые из которых имеют "ужасные" значения, так как они используются логикой ASP для поддержания состояния и для проверки подлинности запроса в некоторой степени. Действительно отправка. Запросы должны отправляться с помощьюметода http POST, поскольку это то, что ожидается от этого приложения ASP. Основная сложность заключается в том, чтобы определить поле формы и связанные с ним значения, которые ожидает ASP (получить страницы с помощью Python - самая простая часть).
Этот код функционален, или, точнее, функционировал, пока я не удалил большую часть значения VSTATE и, возможно, ввел опечатку или два, добавив комментарии.
import urllib
import urllib2
uri = 'http://legistar.council.nyc.gov/Legislation.aspx'
#the http headers are useful to simulate a particular browser (some sites deny
#access to non-browsers (bots, etc.)
#also needed to pass the content type.
headers = {
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8',
'Content-Type': 'application/x-www-form-urlencoded'
}
# we group the form fields and their values in a list (any
# iterable, actually) of name-value tuples. This helps
# with clarity and also makes it easy to later encoding of them.
formFields = (
# the viewstate is actualy 800+ characters in length! I truncated it
# for this sample code. It can be lifted from the first page
# obtained from the site. It may be ok to hardcode this value, or
# it may have to be refreshed each time / each day, by essentially
# running an extra page request and parse, for this specific value.
(r'__VSTATE', r'7TzretNIlrZiKb7EOB3AQE ... ...2qd6g5xD8CGXm5EftXtNPt+H8B'),
# following are more of these ASP form fields
(r'__VIEWSTATE', r''),
(r'__EVENTVALIDATION', r'/wEWDwL+raDpAgKnpt8nAs3q+pQOAs3q/pQOAs3qgpUOAs3qhpUOAoPE36ANAve684YCAoOs79EIAoOs89EIAoOs99EIAoOs39EIAoOs49EIAoOs09EIAoSs99EI6IQ74SEV9n4XbtWm1rEbB6Ic3/M='),
(r'ctl00_RadScriptManager1_HiddenField', ''),
(r'ctl00_tabTop_ClientState', ''),
(r'ctl00_ContentPlaceHolder1_menuMain_ClientState', ''),
(r'ctl00_ContentPlaceHolder1_gridMain_ClientState', ''),
#but then we come to fields of interest: the search
#criteria the collections to search from etc.
# Check boxes
(r'ctl00$ContentPlaceHolder1$chkOptions$0', 'on'), # file number
(r'ctl00$ContentPlaceHolder1$chkOptions$1', 'on'), # Legislative text
(r'ctl00$ContentPlaceHolder1$chkOptions$2', 'on'), # attachement
# etc. (not all listed)
(r'ctl00$ContentPlaceHolder1$txtSearch', 'york'), # Search text
(r'ctl00$ContentPlaceHolder1$lstYears', 'All Years'), # Years to include
(r'ctl00$ContentPlaceHolder1$lstTypeBasic', 'All Types'), #types to include
(r'ctl00$ContentPlaceHolder1$btnSearch', 'Search Legislation') # Search button itself
)
# these have to be encoded
encodedFields = urllib.urlencode(formFields)
req = urllib2.Request(uri, encodedFields, headers)
f= urllib2.urlopen(req) #that's the actual call to the http site.
# *** here would normally be the in-memory parsing of f
# contents, but instead I store this to file
# this is useful during design, allowing to have a
# sample of what is to be parsed in a text editor, for analysis.
try:
fout = open('tmp.htm', 'w')
except:
print('Could not open output file\n')
fout.writelines(f.readlines())
fout.close()
Вот и все для получения начальной страницы. Как сказано выше, тогда нужно будет проанализировать страницу, то есть найти интересующие части и собрать их соответствующим образом и сохранить их в файле /database/whereever. Эту работу можно выполнить очень многими способами: с помощью html-анализаторов или технологий XSLT-типа (даже после анализа html на xml) или даже для простых заданий - с помощью простого регулярного выражения. Кроме того, одним из элементов, который обычно извлекается, является "следующая информация", т.е. своего рода ссылка, которую можно использовать в новом запросе к серверу для получения последующих страниц.
Это должно дать вам грубое представление о том, что такое "длинная стрелка". Есть много других подходов к этому, таких как выделенные утилиты, скрипты в плагине GreaseMonkey Mozilla (FireFox), XSLT...
Большинство сайтов ASP.NET (включая тот, на который вы ссылались) фактически отправляют свои запросы обратно себе, используя глагол HTTP POST, а не глагол GET. Вот почему URL не меняется, как вы заметили.
Что вам нужно сделать, это посмотреть на сгенерированный HTML и захватить все значения их форм. Обязательно запишите все значения формы, так как некоторые из них используются для проверки страницы, и без них ваш запрос POST будет отклонен.
За исключением проверки, страница ASPX в отношении очистки и публикации ничем не отличается от других веб-технологий.
Selenium - отличный инструмент для решения подобных задач. Вы можете указать значения формы, которые вы хотите ввести, и получить html страницы ответа в виде строки в несколько строк кода Python. Используя Selenium, вам может не потребоваться выполнять ручную работу по моделированию действительного почтового запроса и всех его скрытых переменных, как я выяснил после долгих проб и ошибок.
Код в других ответах был полезен; Я бы никогда не смог написать свой сканер без него.
Одна проблема, с которой я столкнулся, была печеньем. Сайт, на котором я сканировал, использовал файлы cookie для регистрации идентификатора сеанса / безопасности, поэтому мне пришлось добавить код, чтобы заставить мой сканер работать:
Добавить этот импорт:
import cookielib
Инициировать файлы cookie:
COOKIEFILE = 'cookies.lwp' # the path and filename that you want to use to save your cookies in
cj = cookielib.LWPCookieJar() # This is a subclass of FileCookieJar that has useful load and save methods
устанавливать CookieJar
так что он используется по умолчанию CookieProcessor
в обработчике открывания по умолчанию:
cj.load(COOKIEFILE)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
Чтобы увидеть, какие куки использует сайт:
print 'These are the cookies we have received so far :'
for index, cookie in enumerate(cj):
print index, ' : ', cookie
Это сохраняет куки:
cj.save(COOKIEFILE) # save the cookies
"Предположим, нам нужно выбрать" все годы "и" все типы "из соответствующих выпадающих меню".
Что эти параметры делают с URL, который в конечном итоге отправляется.
В конце концов, это составляет HTTP-запрос, отправленный через urllib2
,
Вы знаете, как сделать "все годы" и "все типы" из соответствующих выпадающих меню, и выполните следующие действия.
Выберите "все годы" и "все типы" в соответствующих выпадающих меню.
Обратите внимание на URL, который фактически представлен.
Используйте этот URL в
urllib2
,