2017-02-02 4 views
2

Ich versuche, die Dateien von dieser Seite programmatisch zu scrappen: https://olms.dol-esa.gov/query/getYearlyData.do (ja, es wäre wahrscheinlich schneller, sie manuell herunterladen, aber ich möchte lernen, wie das geht).Speichern von Dateien mit WWW :: Mechanize

Ich habe folgendes Stück Code, dies zu versuchen als Test eine der Dateien, um zu versuchen:

#!/usr/bin/perl 
use strict; 
use warnings; 
use WWW::Mechanize; 

my $mech = WWW::Mechanize->new; 

$mech->get('https://olms.dol-esa.gov/query/getYearlyData.do'); 
print $mech->uri(); 
$mech->submit_form(with_fields => { selectedFileName => '/filer/local/cas/YearlyDataDump/2000.zip' }); 

Wenn ich den Code ausführen, passiert nichts. Nichts wird heruntergeladen. JavaScript könnte das Problem sein, ich habe auch den gleichen Code mit WWW :: Mechanize :: Firefox ausprobiert. Auch hier passiert nichts, wenn ich den Code ausführe.

Ich sehe auch nicht die Pfade zu den Dateien. Es ist wahrscheinlich in einigen Javascript verdeckt.

Also, was ist der beste Weg, um diese Dateien zu bekommen? Ist es möglich, sie ohne Javascript zu bekommen?

+0

Deaktivieren Sie JavaScript in Ihrem Browser und Sie werden sehen, dass die Seite ohne sie nutzlos ist, also ist WWW :: Mechanize out. Anstatt WWW :: Mechanize :: Firefox zu verwenden, sollten Sie jedoch prüfen, ob die Daten über eine API verfügbar sind. das ist fast immer eine bessere Wahl als das Kratzen. [Hier] (http://developer.dol.gov/) ist die Hauptseite des Department of Labor API. – ThisSuitIsBlackNot

+0

Ja, mir ist bewusst, dass die Seite ohne JavaScript aktiviert ist.Der Quellcode ist jedoch immer noch da und ich bin gespannt, warum eine POST-Anfrage mit den entsprechenden Feldern, die mit der Anfrage gesendet wurden, nicht dazu führt, dass der Server das Dokument sendet, insbesondere mit WWW :: Mechanize :: Firefox. – StevieD

+1

Schauen Sie sich die Quelle an, in der JS deaktiviert ist: Es gibt kein '' Element, also wird 'submit_form' natürlich nichts tun. Da W :: M :: F nicht funktioniert, haben Sie keinen 'submitButton'-Parameter festgelegt, und es gibt andere Header, die Sie möglicherweise nicht festgelegt haben. Aber genau das sind APIs auch. Sie sollten nicht in den Bauch einer Webseite blättern, die für den menschlichen Konsum gemacht wurde, weil sie sich jederzeit ändern und Ihren Code auf eine Million verschiedene Arten brechen könnte. – ThisSuitIsBlackNot

Antwort

1

Während die Kommentare von ThisSuitIsBlackNot genau richtig sind, gibt es eine ziemlich einfache Möglichkeit, dies programmgesteuert ohne JS überhaupt zu tun. Sie brauchen nicht einmal WWW :: Mechanize.

Ich habe Web::Scraper verwendet, um alle Dateien zu finden. Wie du gesagt hast, sind die Formularwerte da. Es geht darum, sie auszukratzen. WWW :: Mechanize ist gut im Navigieren, aber nicht sehr gut im Scraping. Die Oberfläche von Web :: Scraper ist dagegen wirklich einfach.

Sobald wir die Dateien haben, müssen wir nur eine POST-Anfrage mit den korrekten Formularwerten senden. Dies ist sehr ähnlich zu WWW :: Mechanizes submit_form. In der Tat ist WWW :: Mechanize ein LWP::UserAgent unter der Haube, und alles, was wir brauchen, ist eine Anfrage, also können wir es direkt verwenden.

Die :content_file option auf der post method sagt es, um die Antwort in eine Datei zu setzen. Es wird mit der ZIP-Datei das Richtige tun und es automatisch als Binärdatei schreiben.

use strict; 
use warnings; 
use LWP::UserAgent; 
use Web::Scraper; 
use URI; 

# build a Web::Scraper to find all files on the page 
my $files = scraper { 
    process 'form[name="yearlyDataForm"]', 'action' => '@action'; 
    process 'input[name="selectedFileName"]', 'files[]' => '@value'; 
}; 

# get the files and the form action 
my $res = $files->scrape(URI->new('https://olms.dol-esa.gov/query/getYearlyData.do')); 

# use LWP to download them one by one 
my $ua = LWP::UserAgent->new; 
foreach my $path (@{ $res->{files} }) { 

    # the file will end up relative to the current working directory (.) 
    (my $filename) = (split '/', $path)[-1]; 

    # the submit is hardcoded, but that could be dynamic as well 
    $ua->post(
     $res->{action}, 
     { selectedFileName => $path, submitButton => 'Download' }, 
     ':content_file' => $filename # this downloads the file 
    ); 
} 

Sobald Sie dies ausführen, haben Sie alle Dateien im Verzeichnis Ihres Skripts. Es wird einen Moment dauern und es gibt keine Ausgabe, aber es funktioniert.

Sie müssen sicherstellen, dass der Absenden-Button im Formular enthalten ist.

Da Sie lernen wollten, wie man so etwas macht, habe ich es etwas dynamisch gebaut. Die Formularaktion wird ebenfalls gekratzt, sodass Sie sie in ähnlichen Formularen wiederverwenden können, die dieselben Formularnamen verwenden (oder zu einem Argument machen), und Sie müssen sich nicht um die Formularaktion kümmern. Das Gleiche könnte auch mit der Schaltfläche "Senden" durchgeführt werden, aber Sie müssten sowohl das name als auch das value Attribut verwenden.

Ich wiederhole was ThisSuitIsBlackNot said in their comment though: Scraping einer Website kommt immer mit dem Risiko, dass es später ändert! Für eine einmalige Sache, die egal ist, wenn Sie dies als ein cronjob einmal jährlich ausführen möchten, könnte es nächstes Jahr schon scheitern, weil sie schließlich ihre Website aktualisiert haben, um ein bisschen moderner zu sein.

+1

Sehr genial. Ich bin mit Web :: Scraper vertraut, habe aber nicht daran gedacht, die notwendigen Formularelemente so zu ziehen. Ich habe auch nicht daran gedacht, LWP :: UserAgent so zu benutzen. Ich habe etwas gelernt, wonach ich gesucht habe. Vielen Dank! Ja, mir sind die Grenzen des Scrapings durchaus bewusst. Dies ist eher eine akademische Übung, damit ich meine Fähigkeiten verbessern kann. – StevieD

+0

@StevieD froh, ich könnte helfen. :) – simbabque

Verwandte Themen