刚开始学习PHP,前段时间室友开了一个淘宝店铺,专门定制PPT,然后我准备弄一些邮箱来帮他发发广告什么的,于是就有了接下来的事情。
因为还不会PHP的很多东西,所以做出来的东西也是惨不忍睹,不过总算是可以勉强使用。我的代码的目标是抓取一个贴吧里面所有帖子里面的所有邮箱地址,这是一个听得的工作量,我并没有什么算法基础,所以只有用最笨的for循环来一页一页的用正则表达式匹配。
代码如下:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<form id="form1" name="form1" method="post" action="<?php echo $_SERVER['PHP_SELF'];?>" >
<p align="center">贴吧地址:
<input name="url" type="text" size="70" align="center" />
</p>
<p align="center">
<input type="submit" name="Submit" value="提交" />
</p>
</form>
<?php
if ($_POST["url"]) {
//因为效率太低,读取速度非常慢,所以即使用户关掉浏览器服务器端也会继续执行
ignore_user_abort(true);
//读取网页函数
function readurl($url)
{
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$html = curl_exec($ch);
curl_close($ch);
return $html;
}
//写文本函数
function writelog($str)
{
$open=fopen("log.txt","a" );
fwrite($open,$str);
fclose($open);
}
//$js是已经抓取的邮箱数
$jc=0;
$tburl = $_POST["url"];
//匹配页面共多少个主题的正则表达式
$modepn="/\">(.{1,15})<\/span>个,/";
$html=readurl($tburl);
preg_match_all($modepn,$html , $allpage);
$allpn=$allpage[1][0];
echo "共".$allpn."个主题"."<br>";
$pn=$allpn;
//循环所有页面
for ($nowpn=0; $nowpn <= $allpn ; $nowpn=$nowpn+50) {
$html = readurl($tburl."&pn=".$nowpn);
//匹配当前页的主题数
$mode1="/\/p\/(.{1,10})\" title/i";
$pagenumber=preg_match_all($mode1, $html, $pageurl);
echo "第".$nowpn."页共有".$pagenumber."篇帖子"."<br>";
//循环读取当前页每个主题
for ($n=0; $n < $pagenumber; $n++) {
$purl="http://tieba.baidu.com/p/".$pageurl[1][$n];
$html1=readurl($purl);
$zts=$zts+1;
echo "第".$zts."篇帖子链接:".$purl."<br>";
//匹配当前帖子的总页数
$mode2='/red">(.{1,9})</';
preg_match_all($mode2, $html1, $tzurl);
//$tzpage是单个帖子总页数
$tzpage= $tzurl[1][0];
//循环匹配帖子中当前页的邮箱
for ($m=1; $m <= $tzpage; $m++) {
//匹配邮箱的正则表达式
$mode='/(\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*)</i';
$html2=readurl($purl."?pn=".$m);
echo $purl."?pn=".$m."<br>";
$j=preg_match_all($mode, $html2, $string);
if ($j!=0) {
for ($i=0; $i < $j; $i++) {
echo $string[1][$i]."<br>";
writelog($string[1][$i]."\r\n");
$jc=$jc+1;
}
}
}
}
}
echo "一共获取到",$jc,"条记录";
writelog("一共获取到".$jc."条记录");
}
?>
这个程序现在存在的问题:
1.没有优化算法,三个for循环导致时间复杂度为n^3;
2.正则表达式没有优化,可能会导致匹配效率降低;
3.无法匹配楼中楼的帖子,现在还不懂Javascript,暂时解决不了;
改进:
用客户端数据,因为客户端返回的是JSON数据,要比HTML快,简介,但是我现在对抓包分析以及JSON相关东西还不懂,暂时无法解决;后面版本我会想办法解决上面问题。
目前来说程序基本上是可以正常工作的,虽然是慢了些,但好过没有。