我用PHP编写了一些代码,从。edu域返回html内容。这里简单介绍一下:PHP
中关于网络爬虫的错误当要抓取的链接数量很小(大约40个url)时,爬虫工作得很好,但我在这个数字之后得到"MySQL服务器已经消失"错误。
我将html内容存储为MySQL表中的长文本,我不明白为什么至少40-50个插入后会出现错误。
在这方面的任何帮助都是非常感谢的。
请注意,我已经改变了wait_timeout和max_allowed_packet,以适应我的查询和php代码,现在我不知道该怎么做。请在这方面帮助我。
您可能倾向于通过在查询之前"ping"mysql服务器来处理这个问题。这是个坏主意。要了解更多原因,请查看这篇文章:我应该在每次查询之前ping mysql服务器吗?
处理该问题的最佳方法是将查询包装在try/catch
块中,并捕获任何数据库异常,以便您可以适当地处理它们。这在长时间运行和/或守护程序类型的脚本中尤其重要。所以,这里有一个非常基本的例子,使用"连接管理器"来控制对DB连接的访问:
class DbPool {
private $connections = array();
function addConnection($id, $dsn) {
$this->connections[$id] = array(
'dsn' => $dsn,
'conn' => null
);
}
function getConnection($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
} elseif (isset($this->connections[$id]['conn'])) {
return $this->connections[$id]['conn'];
} else {
try {
// for mysql you need to supply user/pass as well
$conn = new PDO($dsn);
// Tell PDO to throw an exception on error
// (like "MySQL server has gone away")
$conn->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
$this->connections[$id]['conn'] = $conn;
return $conn;
} catch (PDOException $e) {
return false;
}
}
}
function close($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
}
$this->connections[$id]['conn'] = null;
}
}
class Crawler {
private $dbPool;
function __construct(DbPool $dbPool) {
$this->dbPool = $dbPool;
}
function crawl() {
// craw and store data in $crawledData variable
$this->save($crawledData);
}
function saveData($crawledData) {
if (!$conn = $this->dbPool->getConnection('write_conn') {
// doh! couldn't retrieve DB connection ... handle it
} else {
try {
// perform query on the $conn database connection
} catch (Exception $e) {
$msg = $e->getMessage();
if (strstr($msg, 'MySQL server has gone away') {
$this->dbPool->close('write_conn');
$this->saveData($val);
} else {
// some other error occurred
}
}
}
}
}
我有另一个答案,我认为是一个类似的问题,它需要一个类似的答案。基本上,您可以在插入之前使用mysql_ping()
函数来测试连接。在MySQL 5.0.14之前,mysql_ping()
会自动重新连接服务器,但现在你必须建立自己的重新连接逻辑。类似的操作应该可以为您工作:
function check_dbconn($connection) {
if (!mysql_ping($connection)) {
mysql_close($connection);
$connection = mysql_connect('server', 'username', 'password');
mysql_select_db('db',$connection);
}
return $connection;
}
foreach($array as $value) {
$dbconn = check_dbconn($dbconn);
$sql="insert into collected values('".$value."')";
$res=mysql_query($sql, $dbconn);
//then some extra code.
}
我在使用Mysql connector 5.X
时面临"Mysql服务器已经消失"错误,将dll替换到最后一个版本解决了问题。
您是否打开单个DB连接并重用它?有没有可能只是一个简单的暂停?您可能会更好地为每个读/写操作打开一个新的数据库连接(IE contact .edu, get text, open DB, write text, close DB, repeat)。
你是如何使用手柄的?是否有可能它遇到了一个错误,并因此而"消失"?
这就是我现在根据rdlowrey的建议做的,我想这也是对的。
public function url_db_html($sourceLink = NULL, $source) {
$source = mysql_real_escape_string($source);
$query = "INSERT INTO html (id, sourceLink, sourceCode)
VALUES (NULL,('$sourceLink') , ('$source'))";
try {
if(mysql_query($query, $this->connection)==FALSE) {
$msg = mysql_errno($this->connection) . ": " . mysql_error($this->connection);
throw new DbException($msg);
}
} catch (DbException $e) {
echo "<br><br>Catched!!!<br><br>";
if(strstr($e->getMessage(), 'MySQL server has gone away')) {
$this->connection = mysql_connect("localhost", "root", "");
mysql_select_db("crawler1", $this->connection);
}
}
}
因此,一旦查询执行失败,脚本将跳过它,但将确保重新建立连接。
但是,当遇到.jpg, .bmp, .pdf等文件时,我的网络爬虫会崩溃。是否有一种方法可以跳过那些包含这些扩展的url。我正在使用preg_match,并已给出pdf和doc匹配。然而,我希望该函数跳过所有包含扩展名的链接,如mp3, pdf等。这可能吗?