使用Perl来抓取一个网站

use*_*130 8 perl web-scraping

我有兴趣编写一个perl脚本,它转到以下链接并提取数字1975:https://familysearch.org/search/collection/results#count=20&query=%2Bevent_place_level_1%3ACalifornia%20%2Bevent_place_level_2%3A%22San %20Diego%22%20%2Bbirth_year%3A1923-1923〜%20%2Bgender%3AM%20%2Brace%3AWhite&collection_id = 2000219

该网站是1923年出生于加利福尼亚州圣地亚哥县的1923年出生的白人人数.我试图以循环结构来实现这一目标,以概括多个县和出生年份.

在文件locations.txt中,我列出了县,例如圣地亚哥县.

当前代码运行,但不是#1975,它显示未知.1975年的数字应该是$ val \n.

我非常感谢任何帮助!

#!/usr/bin/perl

use strict;

use LWP::Simple;

open(L, "locations26.txt");

my $url = 'https://familysearch.org/search/collection/results#count=20&query=%2Bevent_place_level_1%3A%22California%22%20%2Bevent_place_level_2%3A%22%LOCATION%%22%20%2Bbirth_year%3A%YEAR%-%YEAR%~%20%2Bgender%3AM%20%2Brace%3AWhite&collection_id=2000219';

open(O, ">out26.txt");
 my $oldh = select(O);
 $| = 1;
 select($oldh);
 while (my $location = <L>) {
     chomp($location);
     $location =~ s/ /+/g;
      foreach my $year (1923..1923) {
                 my $u = $url;
                 $u =~ s/%LOCATION%/$location/;
                 $u =~ s/%YEAR%/$year/;
                 #print "$u\n";
                 my $content = get($u);
                 my $val = 'unknown';
                 if ($content =~ / of .strong.([0-9,]+)..strong. /) {
                         $val = $1;
                 }
                 $val =~ s/,//g;
                 $location =~ s/\+/ /g;
                 print "'$location',$year,$val\n";
                 print O "'$location',$year,$val\n";
         }
     }
Run Code Online (Sandbox Code Playgroud)

更新:API不是一个可行的解决方案.我一直与网站开发人员联系.API不适用于该网页的该部分.因此,任何与JSON相关的解决方案都不适用.

Joe*_*ger 8

您的数据似乎是由Javascript生成的,因此LWP无法帮助您.也就是说,您感兴趣的网站似乎有一个开发人员API:https://familysearch.org/developers/

我建议使用Mojo :: URL来构造您的查询,并使用Mojo :: DOMMojo :: JSON来分别解析XML或JSON结果.当然,其他模块也可以工作,但这些工具非常好地集成,让您快速入门.


小智 6

您可以使用WWW :: Mechanize :: Firefox来处理可以由Firefox加载的任何站点.

http://metacpan.org/pod/WWW::Mechanize::Firefox::Examples

您必须安装Mozrepl插件,您才能通过此模块处理网页.基本上你会"远程控制"浏览器.

这是一个例子(也许正在工作)

use strict;
use warnings;
use WWW::Mechanize::Firefox;

my $mech = WWW::Mechanize::Firefox->new(
    activate => 1, # bring the tab to the foreground
);
$mech->get('https://familysearch.org/search/collection/results#count=20&query=%2Bevent_place_level_1%3ACalifornia%20%2Bevent_place_level_2%3A%22San%20Diego%22%20%2Bbirth_year%3A1923-1923~%20%2Bgender%3AM%20%2Brace%3AWhite&collection_id=2000219',':content_file' => 'main.html');

my $retries = 10;
while ($retries-- and ! $mech->is_visible( xpath => '//*[@class="form-submit"]' )) {
      print "Sleep until we find the thing\n";
      sleep 2;
};
die "Timeout" if 0 > $retries;
#fill out the search form
my @forms = $mech->forms();
#<input id="census_bp" name="birth_place" type="text" tabindex="0"/>    
#A selector prefixed with '#' must match the id attribute of the input. A selector prefixed with '.' matches the class attribute. A selector prefixed with '^' or with no prefix matches the name attribute.
$mech->field( birth_place => 'value_for_birth_place' );
# Click on the submit
$mech->click({xpath => '//*[@class="form-submit"]'});
Run Code Online (Sandbox Code Playgroud)

  • 你在聊天中发帖说你找不到文件夹"`bard-mozrepl-abcdefg`".您还发布了一个截图(四次),显示您位于"`bard-mozrepl-abcdefg`"文件夹中,此时我拒绝继续提供帮助.如果你找不到你所在的文件夹,我不打算引导你在perl中编写一个网站刮刀. (3认同)

nan*_*dhp 5

如果您使用浏览器的开发工具,则可以清楚地看到链接到的页面用于获取所需数据的JSON请求。

这个程序应该做你想要的。我添加了许多注释以提高可读性和解释性,并进行了其他一些更改。

use warnings;
use strict;
use LWP::UserAgent;
use JSON;
use CGI qw/escape/;

# Create an LWP User-Agent object for sending HTTP requests.
my $ua = LWP::UserAgent->new;

# Open data files
open(L, 'locations26.txt') or die "Can't open locations: $!";
open(O, '>', 'out26.txt') or die "Can't open output file: $!";

# Enable autoflush on the output file handle
my $oldh = select(O);
$| = 1;
select($oldh);

while (my $location = <L>) {
    # This regular expression is like chomp, but removes both Windows and
    # *nix line-endings, regardless of the system the script is running on.
    $location =~ s/[\r\n]//g;
    foreach my $year (1923..1923) {
        # If you need to add quotes around the location, use "\"$location\"".
        my %args = (LOCATION => $location, YEAR => $year);

        my $url = 'https://familysearch.org/proxy?uri=https%3A%2F%2Ffamilysearch.org%2Fsearch%2Frecords%3Fcount%3D20%26query%3D%252Bevent_place_level_1%253ACalifornia%2520%252Bevent_place_level_2%253A^LOCATION^%2520%252Bbirth_year%253A^YEAR^-^YEAR^~%2520%252Bgender%253AM%2520%252Brace%253AWhite%26collection_id%3D2000219';
        # Note that values need to be doubly-escaped because of the
        # weird way their website is set up (the "/proxy" URL we're
        # requesting is subsequently loading some *other* URL which
        # is provided to "/proxy" as a URL-encoded URL).
        #
        # This regular expression replaces any ^WHATEVER^ in the URL
        # with the double-URL-encoded value of WHATEVER in %args.
        # The /e flag causes the replacement to be evaluated as Perl
        # code. This way I can look data up in a hash and do URL-encoding
        # as part of the regular expression without an extra step.
        $url =~ s/\^([A-Z]+)\^/escape(escape($args{$1}))/ge;
        #print "$url\n";

        # Create an HTTP request object for this URL.
        my $request = HTTP::Request->new(GET => $url);
        # This HTTP header is required. The server outputs garbage if
        # it's not present.
        $request->push_header('Content-Type' => 'application/json');
        # Send the request and check for an error from the server.
        my $response = $ua->request($request);
        die "Error ".$response->code if !$response->is_success;
        # The response should be JSON.
        my $obj = from_json($response->content);
        my $str = "$args{LOCATION},$args{YEAR},$obj->{totalHits}\n";
        print O $str;
        print $str;
    }
}
Run Code Online (Sandbox Code Playgroud)