如何在PHP中实现屏幕抓取工具?

时间:2009-02-10 13:49:57

标签: php javascript screen-scraping

我有一个用户名和密码,可以通过我的程序登录网站。登录后,该网址将从http://localhost/Test/loginpage.html更改为http://www.4wtech.com/csp/web/Employee/Login.csp

如何使用PHP“屏蔽”来自第二个URL的数据?

5 个答案:

答案 0 :(得分:4)

你会使用Curl。 Curl可以登录页面,然后访问新的引用页面并下载整个页面。

查看curl的php手册以及本教程:How to screen-scrape with PHP and Curl

答案 1 :(得分:3)

我不太确定我是否理解你的问题。但是如果你真的打算在PHP中进行屏幕抓取,我推荐使用simple_html_dom解析器。这是一个小型库,可以让你在PHP中使用CSS选择器。对我来说,PHP中的屏幕抓取从未如此简单。这是一个例子:

// Create DOM from URL or file
$html = file_get_html('http://stackoverflow.com/');

// Find all links
foreach($html->find('a') as $element) {
       echo $element->href . '<br>';
}

答案 2 :(得分:0)

为插件道歉,但我写了JS_Extractor用于屏幕抓取。它实际上只是DOM扩展的一个非常简单的扩展,有一些辅助方法可以使事情变得更容易一些,但是效果非常好。

答案 3 :(得分:0)

SimpleTest单元测试框架有Scriptable Browser component,可以单独使用。我通常将它用于屏幕抓取/机器人,因为它能够模拟浏览器。

答案 4 :(得分:0)

重要!

请注意,并非始终允许抓取。如果您决定抓取一个页面,请确保该页面的所有者允许您这样做,否则您最终可能会做一些非法的事情。

假设您被允许刮取页面,请执行以下步骤。

HTTP请求

首先,您发出HTTP请求以获取页面内容。有几种方法可以做到这一点。

的fopen

发送HTTP请求的最基本方法是使用fopen。一个主要优点是您可以设置一次读取的字符数,这在读取非常大的文件时非常有用。但是,这并不是最简单的做法,除非你正在阅读非常大的文件并担心遇到内存问题,否则不建议这样做。

$fp = fopen("http://www.4wtech.com/csp/web/Employee/Login.csp", "rb");
if (FALSE === $fp) {
    exit("Failed to open stream to URL");
}

$result = '';

while (!feof($fp)) {
    $result .= fread($fp, 8192);
}
fclose($fp);
echo $result;

的file_get_contents

最简单的方法就是使用file_get_contents。如果与fopen或多或少相同,但您可以选择较少的选项。这里的一个主要优点是它只需要一行代码。

$result = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
echo $result;

插座

如果您需要更多地控制向服务器发送的标头,您可以将套接字与fopen结合使用。

$fp = fsockopen("www.4wtech.com/csp/web/Employee/Login.csp", 80, $errno, $errstr, 30);
if (!$fp) {
    $result = "$errstr ($errno)<br />\n";
} else {
    $result = '';
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: www.4wtech.com/csp/web/Employee/Login.csp\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
        $result .= fgets($fp, 128);
    }
    fclose($fp);
}
echo $result;

或者,您也可以使用流。流类似于套接字,可以与fopenfile_get_contents结合使用。

$opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: en\r\n" .
              "Cookie: foo=bar\r\n"
  )
);

$context = stream_context_create($opts);

$result = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp', false, $context);
echo result;

卷曲

如果您的服务器支持cURL(通常是这样),则建议使用cURL。使用cURL的一个关键优势是它依赖于其他编程语言中常用的流行C库。它还提供了一种方便的方法来创建请求标头,并自动解析响应标头,并在出现错误时使用简单的界面。

$defaults = array( 
    CURLOPT_URL, "http://www.4wtech.com/csp/web/Employee/Login.csp"
    CURLOPT_HEADER=> 0
);

$ch = curl_init(); 
curl_setopt_array($ch, ($options + $defaults)); 
if( ! $result = curl_exec($ch)) { 
    trigger_error(curl_error($ch)); 
} 
curl_close($ch); 
echo $result; 

或者,您可以使用many PHP libraries之一。我不建议使用库,因为它可能是矫枉过正的。在大多数情况下,最好使用cURL编写自己的HTTP类。

HTML解析

PHP可以方便地将任何HTML加载到DOMDocument

$pagecontent = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
$doc = new DOMDocument();
$doc->loadHTML($pagecontent);
echo $doc->saveHTML();

不幸的是,PHP对HTML5的支持是有限的。如果您在尝试解析页面内容时遇到错误,请考虑使用第三方库。为此,我可以推荐Masterminds/html5-php。使用此库解析HTML文件与使用DOMDocument解析HTML文件非常相似。

use Masterminds\HTML5;

$pagecontent = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
$html5 = new HTML5();
$dom = $html5->loadHTML($html);
echo $html5->saveHTML($dom);

或者,您可以使用例如。我的图书馆PHPPowertools/DOM-Query。它使用Masterminds/html5-php来解析HTML文件以将HTML5字符串解析为DomDocument,并使用symfony/DomCrawler将CSS选择器转换为XPath选择器。即使将一个对象传递给另一个对象,它也始终使用相同的DomDocument,以确保良好的性能。

namespace PowerTools;

// Get file content
$pagecontent = file_get_contents( 'http://www.4wtech.com/csp/web/Employee/Login.csp' );

// Define your DOMCrawler based on file string
$H = new DOM_Query( $pagecontent );

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query( $H->select('body') );

// Passing a string (CSS selector)
$s = $H->select( 'div.foo' );

// Passing an element object (DOM Element)
$s = $H->select( $documentBody );

// Passing a DOM Query object
$s = $H->select( $H->select('p + p') );

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');