Webマイニングに関するあるインタビューに参加したとき、興味深い質問がありました。問題は、Apache Sparkを使用してWebサイトをクロールすることは可能ですか?
Sparkの分散処理能力に対応しているので可能だと思いました。インタビューの後、私はこれを探しましたが、興味深い答えは見つかりませんでした。それはSparkで可能ですか?
この方法はどうですか:
アプリケーションは、クローラーの入力として一連のWebサイトURLを取得します。通常のアプリのみを実装している場合は、次のように実行できます。
for example: you have to crawl www.example.com/news from 20150301 to 20150401, split results can be: [www.example.com/news/20150301, www.example.com/news/20150302, ..., www.example.com/news/20150401]
_www.example.com/news/20150401
_)を単一のスレッドに割り当てます。実際にデータフェッチが行われるのはスレッド内です。アプリケーションがspark 1になると、同じ手順が発生しますが、Sparkの概念:CrawlRDDをカスタマイズして同じスタッフを実行できます。
def getPartitions: Array[Partition]
_は分割タスクを実行するのに適した場所です。def compute(part: Partition, context: TaskContext): Iterator[X]
は、アプリケーションのすべてのエグゼキュータに分散され、並行して実行されます。最終的なプログラムは次のようになります。
_class CrawlPartition(rddId: Int, idx: Int, val baseURL: String) extends Partition {}
class CrawlRDD(baseURL: String, sc: SparkContext) extends RDD[X](sc, Nil) {
override protected def getPartitions: Array[CrawlPartition] = {
val partitions = new ArrayBuffer[CrawlPartition]
//split baseURL to subsets and populate the partitions
partitions.toArray
}
override def compute(part: Partition, context: TaskContext): Iterator[X] = {
val p = part.asInstanceOf[CrawlPartition]
val baseUrl = p.baseURL
new Iterator[X] {
var nextURL = _
override def hasNext: Boolean = {
//logic to find next url if has one, fill in nextURL and return true
// else false
}
override def next(): X = {
//logic to crawl the web page nextURL and return the content in X
}
}
}
}
object Crawl {
def main(args: Array[String]) {
val sparkConf = new SparkConf().setAppName("Crawler")
val sc = new SparkContext(sparkConf)
val crdd = new CrawlRDD("baseURL", sc)
crdd.saveAsTextFile("hdfs://path_here")
sc.stop()
}
}
_
Sparkは、このタスクに本質的に価値を追加しません。
もちろん、分散クロールを実行できますが、優れたクロールツールはすでにこれをすぐにサポートしています。 Sparkによって提供されるRRDなどのデータ構造はここではほとんど役に立ちません。クロールジョブを起動するためだけに、YARN、Mesosなどをより少ないオーバーヘッドで直接使用できます。
確かに、あなたはcould Sparkでこれを行います。チューリング完全であるため、Sparkでワードプロセッサを実行できるのと同じように...しかし、これ以上簡単にはなりません。
はい。
オープンソースプロジェクトをチェックしてください:Sparkler(spark --crawler) https://github.com/USCDataScience/sparkler
チェックアウト Sparkler Internals フロー/パイプライン図。 (申し訳ありませんが、ここに投稿できなかったSVG画像です)
このプロジェクトは、質問が投稿された時点では利用できませんでしたが、2016年12月の時点で、非常に活発なプロジェクトの1つです。
次の部分は、誰かがそのような質問をする理由を理解するのに役立ち、またそれに答えるのに役立ちます。
[1] http://dl.acm.org/citation.cfm?id=2228301
[2] http://nutch.Apache.org/
PS:私はSparklerとコミッターの共同作成者であり、ApacheNutchのPMCです。
Sparklerを設計したときに、Solr/Luceneベースのインデックス付きストレージのプロキシであるRDDを作成しました。これにより、crawler-databse RDDが共有状態に対して非同期のきめ細かい更新を行うことができるようになりました。これがなければ、ネイティブでは不可能です。
受け入れられた答えは、1つの基本的な点で間違っていると思います。実際の大規模なWeb抽出は、プルプロセスです。
これは、多くの場合、HTTPコンテンツを要求する方が、応答を作成するよりもはるかに手間のかからない作業であるためです。私は小さなプログラムを作成しました。このプログラムは、4つのCPUコアと3GB RAMで、1日1600万ページをクロールできますが、あまり最適化されていません。同様のサーバーの場合、このような負荷(〜200 1秒あたりのリクエスト数)は簡単ではなく、通常は多くの最適化レイヤーが必要です。
実際のWebサイトは、たとえば、クロールが速すぎるとキャッシュシステムを壊す可能性があります(最も人気のあるページをキャッシュに入れる代わりに、クロールのロングテールコンテンツで溢れる可能性があります)。その意味で、優れたWebスクレイパーは常にrobots.txtなどを尊重します。
分散クローラーの本当の利点は、1つのドメインのワークロードを分割することではなく、多くのドメインの作業負荷を1つの分散プロセスに分割して、1つのプロセスがシステムが通過する要求の数を自信を持って追跡できるようにすることです。
もちろん、場合によっては、あなたは悪い子になり、ルールを台無しにしたいことがあります。ただし、私の経験では、Webサイトの所有者は、DoS攻撃のように見えるものから資産を保護することを好むため、このような製品は長くは存続しません。
Golangは、ネイティブデータ型としてチャネルを持ち、プルキューを非常によくサポートしているため、Webスクレイパーの構築に非常に適しています。 HTTPプロトコルとスクレイピングは一般に遅いため、プロセスの一部として抽出パイプラインを含めることができます。これにより、データウェアハウスシステムに格納されるデータの量が削減されます。 1つをクロールできますTB 1ドル未満のリソースを使用して、GolangとGoogle Cloudを使用すると高速に実行できます(おそらくAWSとAzureでも実行できます)。
Sparkはあなたに付加価値を与えません。 wget
をクライアントとして使用すると、robots.txtが自動的に適切に尊重されるため、賢い方法です。専門的に作業している場合は、wgetへの並列ドメイン固有のプルキューが最適です。
SpookyStuff というプロジェクトがあります。
Apache Sparkを利用した、Webスクレイピング/データマッシュアップ/アクセプタンスQA用のスケーラブルなクエリエンジン
それが役に立てば幸い!