Come una visione d'insieme, è necessario svolgere quattro compiti principali:
- inviare la richiesta (s) al sito web,
- per recuperare la risposta (s) dal sito
- per analizzare queste risposte
- avere un po 'di logica per scorrere nei compiti di cui sopra, con i parametri associati con la navigazione (alle pagine "Avanti" nella lista dei risultati)
La gestione della richiesta e della risposta http viene eseguita con metodi e classi dalla libreria standard di Python urllib e urllib2. L'analisi delle pagine html può essere fatto con HTMLParser o con altri moduli, come Beautiful Soup
Il seguente frammento della libreria standard di Python dimostra la richiesta e la ricezione di una ricerca presso il sito indicato nella domanda.Questo sito è gestito da ASP e, di conseguenza, è necessario assicurarsi di inviare diversi campi modulo, alcuni dei quali con valori "orribili", in quanto vengono utilizzati dalla logica ASP per mantenere lo stato e per autenticare la richiesta in una certa misura. Effettivamente presentando. Le richieste devono essere inviate con il metodo http POST poiché questo è quello che ci si aspetta da questa applicazione ASP. La difficoltà principale consiste nell'identificare il campo modulo e i valori associati che ASP si aspetta (ottenere le pagine con Python è la parte facile).
Questo codice è funzionale, o più precisamente, era funzionale, fino a quando non ho rimosso la maggior parte del valore VSTATE e possibilmente introdotto un errore di battitura o due aggiungendo commenti.
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()
Questo è tutto per ottenere la pagina iniziale. Come detto sopra, allora bisognerebbe analizzare la pagina, cioè trovare le parti di interesse e riunirle come appropriato, e memorizzarle in un file/database/ovunque. Questo lavoro può essere fatto in molti modi: usando i parser html, o il tipo di tecnologia XSLT (anzi dopo aver analizzato l'html in xml), o anche per i lavori grezzi, semplice espressione regolare. Inoltre, uno degli elementi in genere estratti è la "prossima informazione", cioè un collegamento di ordinamenti, che può essere utilizzato in una nuova richiesta al server per ottenere pagine successive.
Questo dovrebbe darvi un'idea approssimativa di cosa sia lo scraping html "long hand". Ci sono molti altri approcci a questo, come ad esempio gli script dedicati, plug-in GreaseMonkey di Mozilla, XSLT ...
Se utilizzo Google Chrome, come dovrei sostituire il valore di "HTTP_USER_AGENT"? Mi dispiace se questa domanda è stupida dato che non ho fatto molte cose sul web. Grazie! – taocp
@taocp, un modo semplice per sapere quale stringa 'HTTP_USER_AGENT' da usare per un determinato browser è visitare http://www.all-nettools.com/toolbox/environmental-variables-test.php questa pagina ti mostrerà la i valori di intestazione inviati dal browser, cercare "HTTP_USER_AGENT". La stringa effettiva dipende dal sistema operativo, dalla versione specifica e dalla build di Chrome, ma dovrebbe apparire come "Mozilla/5.0" (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, come Gecko) Chrome/29.0.1547.66 Safari/537.36' – mjv
grazie mille per la risposta. Ho provato il tuo codice con i valori corretti impostati sul mio browser Chrome. Il file tmp.htm risultato dice "nessun risultato trovato", mentre quando metto "york" sul sito stesso, ritorna molto. Sai perché? – taocp