获取HTTP请求的最佳方法然后处理HTML响应

时间:2013-11-23 08:51:30

标签: php python c curl domdocument

我正在开发一个需要从其他网站导入数据的项目,然后处理此响应以便能够将其存储在数据库中并将其与其他结果进行比较。

这些网站中的大多数都不提供json和xml提要,因此我发现自己被迫提取HTML文档。

首先,我开始使用CURL获取它们并使用PHP DomDocument&处理响应。 Xpath的。但是我注意到这个过程可能很慢。所以我开始寻找另一种可能更快,更可靠的解决方案,即使它使用的另一种语言如:python,ruby,perl,C等......

代码示例:

  

这只是一个测试代码。在开始这个项目之前。

Init CURL:

public function curlInit($connId, $url , $postString){
    $this->multiConn[$connId] = curl_init($url);
    curl_setopt($this->multiConn[$connId], CURLOPT_RETURNTRANSFER, true);
    curl_setopt($this->multiConn[$connId], CURLOPT_HEADER, false);
    curl_setopt($this->multiConn[$connId], CURLOPT_ENCODING, 'gzip,deflate');

    curl_setopt($this->multiConn[$connId],CURLOPT_POSTFIELDS, $postString);
}

执行请求:

public function multiExec(){
    $this->multiAddHandler();
    $running = null;
    do {
        curl_multi_exec($this->multiHanler, $running);
    } while ($running);
    $i = 0;
    foreach($this->multiConn as $key => $v){
        $this->multiRespose[$key] = curl_multi_getcontent($v);
    }
}

这是执行请求的代码:

public function parse(){
            // first fetch & process the categories
    $this->getCategoryElementList("li");
            // then fetch all events on each category.
    $this->curl->multiExec();
            // parse the events response
    $this->processEvents();
            // after that i have to parse the details of each event.
}

现在,解析HTML响应:

public function getCategoryElementList($tag){
    foreach($this->categoryIdsArr as $group){
        $domElement = $this->getElementById($group);

        $catList = $domElement->childNodes;
        $this->categoryElementList[] = $catList;

        foreach($catList as $cat){
            // temp Var , to check if the subcat_id is autogenerated, so don't init a curl connection for it
            $autoGenSubCatIds = array();
            if($cat->nodeName == 'li'){
                // -- Getting the category name -- //
                $catNameSapn = $this->searchElement($cat, "span", "class", "nav-special-name");

                if(empty($catNameSapn->item(0)->nodeValue)){
                    $catNameSapn = $this->searchElement($cat, "span", "class", "nav-region-name");
                }

                if(isset($catNameSapn->item(0)->nodeValue)){
                    $_categoryName = $catNameSapn->item(0)->nodeValue;
                }
                // autogenerate subcat_id if not exists 
                if($catNameSapn->item(0)->childNodes->item(0)->nodeName == 'a'){
                    $aTag = $catNameSapn->item(0)->childNodes->item(0)->getAttribute("href");
                    $aTag = split("/",$aTag);
                    $_categoryId = $aTag[4];
                }elseif($catNameSapn->item(0)->childNodes->item(0)->nodeName == '#text'){
                    $tempId = 0;
                    array_walk(str_split($_categoryName), function($value, $index) use (&$tempId){
                        $tempId += ord($value);
                    });
                    $_categoryId = ($tempId);
                    $autoGenSubCatIds[] = $tempId;
                }
                // -- End getting the category name -- //
                $this->arrRes['category'][$_categoryId]['category_name'] = $_categoryName;
                $this->arrRes['category'][$_categoryId]['category_id'] = $_categoryId;

                $subCats = $cat->getElementsByTagName("a");
                foreach($subCats as $subCat){
                    $_subCategroyName = $subCat->nodeValue;
                    $aTag = $subCat->getAttribute("href");
                    $aTag = split("/",$aTag);
                    $_subCategoryId = $aTag[4];

                    $this->arrRes['category'][$_categoryId]['subcat'][$_subCategoryId]['subcat_name'] = $_subCategroyName;
                    $this->arrRes['category'][$_categoryId]['subcat'][$_subCategoryId]['subcat_id'] = $_subCategoryId;

                    if(!in_array($_subCategoryId, $autoGenSubCatIds))
                        $this->curl->curlInit($_subCategoryId, "https://********************.com", "Ids=$_subCategoryId&stId=4&page=0");

                }
            }

        }
    }
}

我的问题不仅仅是关于此代码。我正在寻找最佳方法来计算连接数并解析它们。

1 个答案:

答案 0 :(得分:0)

您描述的过程主要涉及三个部分:

  1. 从互联网上获取HTML文档
  2. 解析html
  3. 将解析后的结果存储在数据库中
  4. 该过程的第一部分主要取决于您的网络连接,服务器的响应时间等。无论您使用何种语言/技术,都会产生很大的不同,因为大部分时间花在低级系统调用和网络延迟。

    第三部分也主要是关于你的数据库引擎性能,即使你可以在这里和那里进行一些优化(如何构建查询,如何管理事务,如果你保持持久连接或每次重新连接等)。

    这将为您提供HTML解析部分。如果它是格式良好的HTML,那么你可以使用C语言实现的几个非常优化的解析器(即Python与libxml2和libxslt的lxml绑定)。您编写代码的方式也有可能进行优化(一般情况下 - 不是在讨论我上面没有阅读的上述代码段)但是如何这样做取决于您使用的确切语言/技术。 / p>

    现在重点是无论如何优化解析器和您自己的代码,您仍然会受到网络和数据库性能的束缚。在这里获得更好性能的唯一方法是尽可能地并行化进程,尽可能多的节点上的HTTP客户端根据需要在尽可能多的节点上提供解析器,它们自己为数据库提供数据。

    我们在使用Celery和RabbitMQ进行并行化的Python应用程序中解决了一个非常类似的问题,平衡了4个不同的" worker"节点(加上一个用于数据库,一个用于Django / apache前端),但在大多数语言/技术中都有同样好的甚至更好的解决方案(MapReduce任何人?)。