it-swarm-ja.com

特定のGoogleブックをWebスクレイピング/クロールする

私の仕事では、Googleブックスの大きな本からテキストを削り取る必要があります。問題の本は非常に古い本であり、著作権の対象外です。この本は世界の地名集です。テキストをデータベースに入れるので、PDFではなく生のテキストが必要です。

私はすでに、このタスクを完了するために使用できるツールとテクニックの研究に多くの時間を費やしてきました。私は圧倒され、どこから始めればよいのか、どちらが最善/最も簡単な方法であるのかわかりません。行き止まりでこれ以上時間を無駄にしたくありません。

問題は2つの部分に分けることができます:

  1. ページをクロールします。
  2. データのダウンロード。

私が最もこだわっているのは本当にパート(1)です。データを取得したら(生のhtmlページのみであっても)、パーサーを使用して必要なものを抽出できると確信しています。

ページのナビゲートは、続行または矢印をクリックして行います。ページの増分は常に一貫しているわけではなく、一部のページには画像が埋め込まれているため、変動する可能性があります。したがって、必ずしも次のURLを予測できるとは限りません。本の第1巻の最初のURLは次のとおりです。

http://books.google.co.uk/books?id=grENAAAAQAAJ&pg=PR5&output=text

JavaとJavaScriptでプログラミングでき、Pythonの基本的な知識があります。node.jsやscrapyなどを検討しました。wgetを試しましたが、401の非認証アクセスエラーが発生しました。また、 iRobot、GreaseMonkey、FoxySpiderを試しました。

2
user2661243

Node.jsに小さなプログラム(extract.jsと呼ばれる)を記述してテキストをスクレイプすることで、この問題を解決しました。私はこのページを助けてくれました: http://blog.miguelgrinberg.com/post/easy-web-scraping-with-nodejs

各htmlページには、複数の本のページが含まれています。したがって、URLのページパラメータを1だけインクリメントすると、注意しないと重複する本のページをスクレイピングすることになります(これは私が特にこだわった部分でした)。 jqueryセレクターを使用して、URLで指定された個々の本のページのみを選択し、htmlに存在する他の本のページを無視することでこれを回避しました。このようにして、スプレッドシートプログラムを使用して、各単一ページのURLを順番に使用してテキストファイルをすばやく作成できました(増分は1つしかないため)。

これまでのところ、最初の2つのボリューム、残り5つのボリュームを正常にスクレイピングしました。コードを以下に示します。これは、他のGoogleブックスをスクレイピングするための便利なスターターとして役立つ可能性があります。

// Usage: node extract.js input output
// where input (mandatory) is the text file containing your list of urls
// and output (optional) is the directory where the output files will be saved

var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

// Read the command line parameters
var input = process.argv[2];
var output = process.argv[3];

if (!input) {
  console.log("Missing input parameter");
  return;
}

// Read the url input file, each url is on a new line
var urls = fs.readFileSync(input).toString().split('\n');

// Check for non urls and remove
for (var i = 0; i < urls.length; i++) {
  if (urls[i].slice(0, 4) != 'http') {
    urls.splice(i, 1);
  }
}

// Iterate through the urls
for (var i = 0; i < urls.length; i++) {
  var url = urls[i];

  // request function is asynchronous, hence requirement for self-executing function
  // Cannot guarantee the execution order of the callback for each url, therefore save results to separate files 
  request(url, ( function(url) {
            return function(err, resp, body) {
                if (err)
                    throw err;

                // Extract the pg parameter (book page) from the url
                // We will use this to only extract the text from this book page
                // because a retrieved html page contains multiple book pages
                var pg = url.slice(url.indexOf('pg=') + 3, url.indexOf('&output=text'));

                //
                // Define the filename
                //
                var number = pg.slice(2, pg.length);
                var zeroes = 4 - number.length;

                // Insert leading zeroes
                for (var j = 0; j < zeroes; j++) {
                  number = '0' + number;
                }  

                var filename = pg.slice(0, 2) + number + '.txt';

                // Add path to filename
                if (output) {
                  if (!fs.existsSync(output))
                    fs.mkdirSync(output);

                  filename = output + '/' + filename;
                }

                // Delete the file if it already exists
                if (fs.existsSync(filename))
                  fs.unlinkSync(filename);

                // Make the DOM available to jquery
                $ = cheerio.load(body);

                // Select the book page
                // Pages are contained within 'div' elements (where class='flow'),
                // each of which contains an 'a' element where id is equal to the page
                // Use ^ to match pages because sometimes page ids can have a trailing hyphen and extra characters
            var page = $('div.flow:has(a[id=' + pg + ']), div.flow:has(a[id^=' + pg + '-])');

            //
            // Extract and save the text of the book page to the file
            //

            var hasText = false;

            // Text is in 'gtxt_body', 'gtxt_column' and 'gtxt_footnote'
            page.find('div.gtxt_body, div.gtxt_column, div.gtxt_footnote').each(function() {  
              this.find('p.gtxt_body, p.gtxt_column, p.gtxt_footnote').each(function() {
                hasText = true;

                fs.appendFileSync(filename, this.text());
                fs.appendFileSync(filename, '\n\n');
              });
            });

                // Log progress
                if (hasText) {
                  console.log("Retrieved and saved page: " + pg);
                }
                else {
                  console.log("Skipping page: " + pg);
                }
            }
        } )(url));
}
1
user2661243

download "Gazetteer of the World" dictionary of geographic knowledgeでGoogle検索を行うと、たとえば、 PDF、次にPDF2Wordのようなものを使用してテキストを抽出できます。

PDFがすべての写真である;-)でない限り、pdf2jpgで抽出して、OCRプログラムで画像ファイルをフィードすることができます。

それらを購入して(Amazonにはいくつかのヒットがあります)、ページを切り取り、自動フィードとOCRを備えたスキャナーに通すこともできます。

これは1回限りの作業なので、プログラミングは私の最後の手段になります。

最初に(6?)ボリュームを取得できる形式のインベントリを作成し、これらの形式を処理するためのコストと作業量の見積もりを作成すると役立つ場合があります。

1
Jan Doggen