方法一
通过fopen和stream_get_contents获取html内容
从给定的url获取html内容
/**
* 爬虫程序 -- 原型
* 从给定的url获取html内容
* 通过fopen和stream_get_contents获取html内容
* @param string $url
* @return string
*/
function _getUrlContent($url)
{
//fopen() 函数打开一个文件或 URL。
$handle = fopen($url, "r");
// var_dump($handle);die;
if ($handle) {
//官方是这样描述的与 stream_get_contents();file_get_contents() 一样,但是 stream_get_contents() 是对一个已经打开的资源流进行操作,并将其内容写入一个字符串返回
$content = stream_get_contents($handle, 1024 * 1024);
return $content;
} else {
return false;
}
}
从html内容中筛选链接。爬取信息,可直接调用
/**
* 从html内容中筛选链接。爬取信息,可直接调用
* @param string $web_content
* @param [type] $tag [要查找的标签]
* @param [type] $attr [要查找的属性名]
* @param [type] $value [属性名对应的值]
* @return array
*/
function _filterUrl($web_content)
{
$tag = 'div';
$attr = '';
$value = '';
//自定义正则表达式
$reg_tag_a = "/<$tag.*?$attr=\".*?$value.*?\".*?>(.*?)<\/$tag>/is";
//获取页面所有链接的正则表达式
//$reg_tag_a = "/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/";
//preg_match_all 函数用于执行一个全局正则表达式匹配。
//参数一:$pattern: 要搜索的模式,字符串形式。
//参数二:$subject: 输入字符串。
//参数三:$matches: 多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定。
//参数四:$flags:匹配模式,默认PREG_PATTERN_ORDER
$result = preg_match_all($reg_tag_a, $web_content, $match_result);
if ($result) {
//匹配结果
return $match_result[1];
}
}
修正相对路径,(可不使用)
/**
* 修正相对路径,(可不使用)
* @param string $base_url
* @param array $url_list
* @return array
*/
function _reviseUrl($base_url, $url_list)
{
$url_info = parse_url($base_url);
// var_dump($url_info);die;
$base_url = $url_info["scheme"] . '://';
if (isset($url_info["user"]) && isset($url_info["pass"])) {
$base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
}
$base_url .= $url_info["host"];
if (isset($url_info["port"])) {
$base_url .= ":" . $url_info["port"];
}
$base_url .= $url_info["path"];
// print_r($url_list);
if (is_array($url_list)) {
foreach ($url_list as $url_item) {
if (preg_match('/^http/', $url_item)) {
// 已经是完整的url
$result[] = $url_item;
} else {
// 不完整的url
$real_url = $base_url . '/' . $url_item;
$result[] = $real_url;
}
}
return $result;
} else {
return;
}
}
修正链接,可不调用,直接调用_filterUrl
/**
* 爬虫 其实就是修正链接,可不调用,直接调用_filterUrl
* @param string $url
* @return array
*/
function crawler($url)
{
// $url = g('url') ?? '';
$content = $this->_getUrlContent($url);
// var_dump($content);die;
if ($content) {
$url_list = $this->_reviseUrl($url, $this->_filterUrl($content));
// var_dump($url_list);die;
if ($url_list) {
return $url_list;
} else {
return;
}
} else {
return;
}
}
测试用主程序,往文件里写入爬虫信息
/**
* 测试用主程序,往文件里写入爬虫信息
*/
public function main()
{
$current_url = "https://www.sina.com.cn/"; //初始url
$fp_puts = fopen("url3.txt", "ab"); //记录url列表
$fp_gets = fopen("url3.txt", "r"); //保存url列表
do {
$result_url_arr = $this->crawler($current_url);
// var_dump($result_url_arr);die;
if ($result_url_arr) {
foreach ($result_url_arr as $url) {
fputs($fp_puts, $url . "\r\n");
}
}
} while ($current_url = fgets($fp_gets, 1024)); //不断获得url
}
方法二
使用curl获取html页面内容
使用curl获取html页面内容
/**
* [curlHtml 获取页面信息]
* 使用curl获取html页面内容
* @param [type] $url [网址]
* @return [type] [description]
*/
function curlHtml($url)
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "{$url}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding: gzip, deflate, br",
"Accept-Language: zh-CN,zh;q=0.9",
"Cache-Control: no-cache",
"Connection: keep-alive",
"Pragma: no-cache",
"Upgrade-Insecure-Requests: 1",
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"cache-control: no-cache"
),
));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) return false;
else return $response;
}
使用正则获取html内容中指定的内容
/**
* [get_tag_data 使用正则获取html内容中指定的内容]
* @param [type] $html [爬取的页面内容]
* @param [type] $tag [要查找的标签]
* @param [type] $attr [要查找的属性名]
* @param [type] $value [属性名对应的值]
* @return [type] [description]
*/
function get_tag_data($html, $tag, $attr, $value)
{
// var_dump($tag, $attr, $value);
$regex = "/<$tag.*?$attr=\".*?$value.*?\".*?>(.*?)<\/$tag>/is";
// var_dump($regex);
preg_match_all($regex, $html, $matches, PREG_PATTERN_ORDER);
var_dump($matches);die;
$data = isset($matches[1]) ? $matches[1] : '';
// var_dump($data);die;
return $data;
}
使用xpath对获取到的html内容进行处理
/**
* [get_html_data 使用xpath对获取到的html内容进行处理]
* @param [type] $html [爬取的页面内容]
* @param [type] $path [Xpath语句]
* @param integer $tag [类型 0内容 1标签内容 自定义标签]
* @param boolean $type [单个 还是多个(默认单个时输出单个)]
* @return [type] [description]
*/
function get_html_data($html, $path, $tag = 1, $type = true)
{
$dom = new \DOMDocument();
@$dom->loadHTML("<?xml encoding='UTF-8'>" . $html); // 从一个字符串加载HTML并设置UTF8编码
$dom->normalize(); // 使该HTML规范化
$xpath = new \DOMXPath($dom); //用DOMXpath加载DOM,用于查询
$contents = $xpath->query($path); // 获取所有内容
$data = [];
foreach ($contents as $value) {
if ($tag == 1) {
$data[] = $value->nodeValue; // 获取不带标签内容
} elseif ($tag == 2) {
$data[] = $dom->saveHtml($value); // 获取带标签内容
} else {
$data[] = $value->attributes->getNamedItem($tag)->nodeValue; // 获取attr内容
}
}
if (count($data) == 1) {
$data = $data[0];
}
return $data;
}
测试程序,调用
//调用
public function get_content()
{
$url = g('url') ?? '';
$tag = g('tag') ?? '';
$attr = g('attr') ?? '';
$value = g('value') ?? '';
if (empty($url) || empty($tag)) {
resultInfo(4, '缺少关键参数!');
}
$html = $this->curlHtml($url);
//使用正则获取
$data = $this->get_tag_data($html, $tag, $attr, $value);
//Xpath方法,暂未搞明白
// $data = $this->get_html_data($html, $path, $tag = 1, $type = true);
resultInfo(1, 'ok!', $data);
}