Mos*_*she 12 php performance domdocument
我正在使用cURL从服务器中提取网页.我将它传递给Tidy并将输出抛出到DOMDocument中.然后麻烦开始了.
该网页包含大约三千个(yikes)表标签,我正在从中抓取数据.有两种表,其中一种或多种类型B遵循类型A.
我用microtome(true)
调用来描述我的脚本.我在脚本的每个阶段之前和之后都进行了调用,并相互减去了时间.所以,如果你跟着我完成我的代码,我会解释它,分享个人资料结果,并指出问题所在.也许你甚至可以帮我解决问题.开始了:
首先,我包含两个文件.一个处理一些解析,另一个定义两个"数据结构"类.
// Imports
include('./course.php');
include('./utils.php');
Run Code Online (Sandbox Code Playgroud)
据我所知,包含是无关紧要的,所以让我们继续进行cURL导入.
// Execute cURL
$response = curl_exec($curl_handle);
Run Code Online (Sandbox Code Playgroud)
我已经将cURL配置为不超时,并发布一些标题数据,这是获得有意义的响应所必需的.接下来,我清理数据以准备DOMDocument.
// Run about 25 str_replace calls here, to clean up
// then run tidy.
$html = $response;
//
// Prepare some config for tidy
//
$config = array(
'indent' => true,
'output-xhtml' => true,
'wrap' => 200);
//
// Tidy up the HTML
//
$tidy = new tidy;
$tidy->parseString($html, $config, 'utf8');
$tidy->cleanRepair();
$html = $tidy;
Run Code Online (Sandbox Code Playgroud)
到目前为止,代码大约需要9秒钟.考虑到这是一个cron工作,不经常运行,我很好.但是,代码的下一部分确实是barfs.这是我从HTML中获取我想要的内容并将其推送到我的自定义类中.(我计划将其填入MySQL数据库,但这是第一步.)
// Get all of the tables in the page
$tables = $dom->getElementsByTagName('table');
// Create a buffer for the courses
$courses = array();
// Iterate
$numberOfTables = $tables->length;
for ($i=1; $i <$numberOfTables ; $i++) {
$sectionTable = $tables->item($i);
$courseTable = $tables->item($i-1);
// We've found a course table, parse it.
if (elementIsACourseSectionTable($sectionTable)) {
$course = courseFromTable($courseTable);
$course = addSectionsToCourseUsingTable($course, $sectionTable);
$courses[] = $course;
}
}
Run Code Online (Sandbox Code Playgroud)
作为参考,这是我调用的实用程序函数:
//
// Tell us if a given element is
// a course section table.
//
function elementIsACourseSectionTable(DOMElement $element){
$tableHasClass = $element->hasAttribute('class');
$tableIsCourseTable = $element->getAttribute("class") == "coursetable";
return $tableHasClass && $tableIsCourseTable;
}
//
// Takes a table and parses it into an
// instance of the Course class.
//
function courseFromTable(DOMElement $table){
$secondRow = $table->getElementsByTagName('tr')->item(1);
$cells = $secondRow->getElementsByTagName('td');
$course = new Course;
$course->startDate = valueForElementInList(0, $cells);
$course->endDate = valueForElementInList(1, $cells);
$course->name = valueForElementInList(2, $cells);
$course->description = valueForElementInList(3, $cells);
$course->credits = valueForElementInList(4, $cells);
$course->hours = valueForElementInList(5, $cells);
$course->division = valueForElementInList(6, $cells);
$course->subject = valueForElementInList(7, $cells);
return $course;
}
//
// Takes a table and parses it into an
// instance of the Section class.
//
function sectionFromRow(DOMElement $row){
$cells = $row->getElementsByTagName('td');
//
// Skip any row with a single cell
//
if ($cells->length == 1) {
# code...
return NULL;
}
//
// Skip header rows
//
if (valueForElementInList(0, $cells) == "Section" || valueForElementInList(0, $cells) == "") {
return NULL;
}
$section = new Section;
$section->section = valueForElementInList(0, $cells);
$section->code = valueForElementInList(1, $cells);
$section->openSeats = valueForElementInList(2, $cells);
$section->dayAndTime = valueForElementInList(3, $cells);
$section->instructor = valueForElementInList(4, $cells);
$section->buildingAndRoom = valueForElementInList(5, $cells);
$section->isOnline = valueForElementInList(6, $cells);
return $section;
}
//
// Take a table containing course sections
// and parse it put the results into a
// give course object.
//
function addSectionsToCourseUsingTable(Course $course, DOMElement $table){
$rows = $table->getElementsByTagName('tr');
$numRows = $rows->length;
for ($i=0; $i < $numRows; $i++) {
$section = sectionFromRow($rows->item($i));
// Make sure we have an array to put sections into
if (is_null($course->sections)) {
$course->sections = array();
}
// Skip "meta" rows, since they're not really sections
if (is_null($section)) {
continue;
}
$course->addSection($section);
}
return $course;
}
//
// Returns the text from a cell
// with a
//
function valueForElementInList($index, $list){
$value = $list->item($index)->nodeValue;
$value = trim($value);
return $value;
}
Run Code Online (Sandbox Code Playgroud)
此代码需要63秒.PHP脚本从网页中提取数据的时间超过一分钟.啧!
我被建议分开我的主要工作循环的工作量,但考虑到我的数据的同质性,我不完全确定如何.任何有关改进此代码的建议都非常感谢.
我该怎么做才能改善代码执行时间?
Mos*_*she 12
事实证明,我的循环非常低效.
使用foreach
切割时间在一半到约31秒.但那还不够快.所以我对一些样条曲线进行了网络化,并与大约一半的程序员进行了一些头脑风暴,我知道如何在网上戳.这是我们发现的:
使用DOMNodeList的item()
访问器是线性的,在循环中产生指数级缓慢的处理时间.因此,在每次迭代后删除第一个元素会使循环更快.现在,我们总是访问列表的第一个元素.这让我降到了8秒.
在玩了一些之后,我意识到它的->length
性质DOMNodeList
同样糟糕item()
,因为它也会产生线性成本.所以我将for循环更改为:
$table = $tables->item(0);
while ($table != NULL) {
$table = $tables->item(0);
if ($table === NULL) {
break;
}
//
// We've found a section table, parse it.
//
if (elementIsACourseSectionTable($table)) {
$course = addSectionsToCourseUsingTable($course, $table);
}
//
// Skip the last table if it's not a course section
//
else if(elementIsCourseHeaderTable($table)){
$course = courseFromTable($table);
$courses[] = $course;
}
//
// Remove the first item from the list
//
$first = $tables->item(0);
$first->parentNode->removeChild($first);
//
// Get the next table to parse
//
$table = $tables->item(0);
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已针对我想要的数据进行了一些其他优化,但相关部分是我如何处理从一个项目到下一个项目的进展.
归档时间: |
|
查看次数: |
1506 次 |
最近记录: |