【问题标题】:crawling scraping and threading? with php爬行刮和穿线?用 php
【发布时间】:2009-06-08 17:02:29
【问题描述】:

我有一个个人网站,它从我最喜欢的音乐博客中抓取和收集 MP3 以供以后收听...

它的工作方式是 CRON 作业每分钟运行一次 .php 脚本,以抓取数据库中的下一个博客。结果被放入数据库,然后第二个 .php 脚本抓取收集到的链接。

脚本只向下爬入页面的两个级别,因此.. 主页 www.url.com 和该页面上的链接 www.url.com/post1 www.url.com/post2

我的问题是,当我开始收集更多的博客时。它们每 20 到 30 分钟只被扫描一次,当我将新博客添加到脚本中时,会在扫描链接时进行备份,因为每分钟只处理一个。

由于 PHP 的工作方式,由于脚本执行时间的原因,我似乎不能只允许脚本处理多个或有限数量的链接。内存限制。超时等。

我也不能运行同一脚本的多个实例,因为它们会在数据库中相互覆盖。

我可以加快这个过程的最佳方法是什么。

有没有一种方法可以让多个脚本影响数据库但写入它们以便它们不会相互覆盖但将结果排队?

有没有办法在 PHP 中创建线程,以便脚本可以按照自己的节奏处理链接?

有什么想法吗?

谢谢。

【问题讨论】:

  • 我不太确定我是否理解你的问题,但你能不能在你的 php 脚本的不同实例之间拆分博客站点列表并独立运行它们?如果您有一个脚本覆盖了另一个的数据库条目,那么您可能应该重新考虑您的数据库设计。
  • 一个名为 import.io 的现有网络应用可能在这里有用(我与他们没有任何关系)

标签: php multithreading screen-scraping web-crawler


【解决方案1】:

多使用卷曲!

Curl-mutli 可以让你并行处理页面。

http://us3.php.net/curl

您大部分时间都在网站上等待,进行 db 插入和 html 解析的速度要快几个数量级。

你创建了一个你想要抓取的博客列表,将它们发送到 curl multi。等待然后串行处理所有调用的结果。然后,您可以在下一层进行第二次传递

http://www.developertutorials.com/blog/php/parallel-web-scraping-in-php-curl-multi-functions-375/

【讨论】:

    【解决方案2】:

    运行并行扫描器的伪代码:

    start_a_scan(){
        //Start mysql transaction (needs InnoDB afaik)        
        BEGIN 
            //Get first entry that has timed out and is not being scanned by someone
            //(And acquire an exclusive lock on affected rows)
            $row = SELECT * FROM scan_targets WHERE being_scanned = false AND \
                    (scanned_at + 60) < (NOW()+0) ORDER BY scanned_at ASC \
                          LIMIT 1 FOR UPDATE
            //let everyone know we're scanning this one, so they'll keep out
            UPDATE scan_targets SET being_scanned = true WHERE id = $row['id']
        //Commit transaction
        COMMIT
        //scan
        scan_target($row['url'])
        //update entry state to allow it to be scanned in the future again
        UPDATE scan_targets SET being_scanned = false, \
                  scanned_at = NOW() WHERE id = $row['id']
    }
    

    您可能需要一个“清理器”来定期检查是否还有任何已中止的扫描挂起,并重置它们的状态以便再次扫描它们。

    然后您可以让多个扫描进程并行运行!耶!

    干杯!

    编辑:我忘记了您需要使用 FOR UPDATE 进行第一个 SELECT。阅读更多here

    【讨论】:

    • 嘿,谢谢。有些东西我不知道,但我会读一读。
    • NP,请阅读,然后在 SO 上返回此处并填写空白 :)
    【解决方案3】:

    这肯定不是您问题的答案,但如果您愿意学习 python,我建议您查看 Scrapy, an open source web crawler/scraper framework,它应该可以满足您的需求。同样,它不是 PHP,而是 Python。它是多么可分配等等......我自己使用它。

    【讨论】:

    • 是的,我一直很确定 PHP 不是编写此代码的最佳语言,但它是我所知道的。将看看scrapy。
    • @ian:很高兴看到您愿意使用其他工具。在 Python 中处理异步处理的方法有很多。
    【解决方案4】:

    由于 PHP 的工作方式,由于脚本执行时间的原因,我似乎不能只允许脚本处理多个或有限数量的链接。内存限制。超时等。

    内存限制只是一个问题,如果您的代码泄漏内存。您应该解决这个问题,而不是提高内存限制。脚本执行时间是一种安全措施,您可以简单地为您的 cli 脚本禁用它。

    我也不能运行同一脚本的多个实例,因为它们会在数据库中相互覆盖。

    您可以以实例不会相互覆盖的方式构建您的应用程序。一种典型的方法是按站点进行分区;例如。为您要抓取的每个站点启动一个单独的脚本。

    【讨论】:

      【解决方案5】:

      CLI 脚本不受最大执行时间的限制。内存限制通常不是问题,除非您在内存中随时都有大量数据。超时应该由您的应用程序优雅地处理。

      应该可以更改您的代码,以便您可以一次运行多个实例 - 不过,您必须发布脚本以供任何人进一步建议。正如彼得所说,您可能需要查看设计。在 pastebin 中提供代码将有助于我们为您提供帮助:)

      【讨论】:

      • 我想主要问题是如果我运行两个或多个实例 say: scan.php 每分钟然后两个或每个将同时从数据库中读取相同的值..下一个链接到爬网,所以我没有得到额外的速度,只是错误或错误的结果而不是队列。
      • @ian:也许我想错了:你能不能每个站点有一个数据库表,并运行一个单独的脚本来处理每个表中的链接?
      • @Adam:嗯。我想我可以...链接在一起的唯一原因是脚本知道接下来要处理的正确链接...这很好,因为即使是流行音乐博客也不太可能每天更新一次以上所以好像没有大量的链接要通过。我不能用我的服务器自动创建 CRON 作业,所以这可能是一个问题....
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多