我正在使用 cURL 从服务器中提取网页。我将它传递给 Tidy 并将输出放入 DOMDocument。然后麻烦就开始了。
该网页包含大约三千个(yikes)表格标签,我正在从中抓取数据。有两种类型的表,其中一个或多个类型 B 跟随类型 A。
我已经使用microtome(true)
调用分析了我的脚本。我在脚本的每个阶段之前和之后都进行了调用,并相互减去了时间。所以,如果你跟着我看我的代码,我会解释它,分享配置文件结果,并指出问题所在。也许你甚至可以帮我解决问题。开始了:
首先,我包含两个文件。一个处理一些解析,另一个定义两个“数据结构”类。
// Imports
include('./course.php');
include('./utils.php');
据我所知,包含是无关紧要的,所以让我们继续进行 cURL 导入。
// Execute cURL
$response = curl_exec($curl_handle);
我已将 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;
到目前为止,该代码已经花费了大约 9 秒。考虑到这是一项 cron 工作,不经常运行,我对此很好。但是,代码的下一部分真的很糟糕。这是我从 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;
}
}
作为参考,这是我调用的实用程序函数:
//
// 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;
}
此代码需要 63 秒。PHP 脚本从网页中提取数据需要一分钟多的时间。嘘!
有人建议我拆分主要工作循环的工作量,但考虑到我的数据的同质性,我不完全确定该怎么做。非常感谢任何有关改进此代码的建议。
我可以做些什么来改善我的代码执行时间?