Я на самом деле пытаюсь создать сайт, похожий на этот:
https://robhammond.co/tools/seo-crawler
Концепция проста: вы вводите URL веб-сайта, и он следует за каждой ссылкой, которая у вас есть внутри, чтобы увидеть, есть ли мертвые ссылки.
Я пытался сделать это рекурсивно: просматривая одну страницу, находя ссылки и просматривая каждую найденную ссылку, находя ссылки на каждой странице и т. Д.
Я создал массив уже посещенных ссылок, поэтому я не буду проверять страницы, которые уже проверил.
Вот мой код, я использую рекурсивный ajax-вызов PHP-файла, который использует cURL, чтобы получить код ошибки и найти все ссылки внутри него. После этого я делаю еще один вызов ajax для каждой найденной ссылки.
Вот мой код:
Мой html / javascript файл:
<?php
session_start();
$_SESSION['visitedLinks'] = [];
?>
<html lang="fr">
<header>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<title>Kaiman Crawler</title>
</header>
<body>
<form id="form" method="post" action="">
<label>
Veuillez saisir l'URL du site à scanner :
<input type="text" id='url' value="https://php.net/" required/>
</label>
<input type="submit" value="Scanner"/>
</form>
<p>Attention: Les pages avec plus de 200 liens ne seront pas traitées</p>
<table class="table" hidden>
<thead>
<tr>
<th scope="col"></th>
<th scope="col">URL</th>
<th scope="col">Titre de la page</th>
<th scope="col">Statut</th>
<th scope="col">Signification</th>
<th scope="col">Nombre de liens sur la page</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
var cpt =1;
var request = 0;
var baseURL;
function signification(code){
switch (code) {
// TODO: Continuer les codes d'erreur
case 200:
return "Accessible";
case 404:
return "Page introuvable";
}
}
function scanPage(url) {
$.ajax({
url: 'getURLs.php',
dataType:'json',
type:'POST',
data:{
URL: url
}
}).done(function (data) {
console.log(data);
if (data['success']) {
$('tbody').append('<tr id="' + cpt + '"></tr>');
$('#' + cpt).append("<td>" + cpt++ + "</td>")
.append("<td>" + data['page'].url + "</td>")
.append("<td>" + data['page'].titre + "</td>")
.append("<td>" + data['page'].code + "</td>")
.append("<td>" + signification(data['page'].code) + "</td>")
.append("<td>" + data['page']['pages'].length + "</td>");
for (let i = 0; i < data['page']['pages'].length; ++i) {
if (data['page']['pages'].length >= 200){
break;
}
if (!data['links'].includes(data['page']['pages'][i]) && data['links'].includes(baseURL)) {
console.log(++request);
scanPage(data['page']['pages'][i]);
}
}
}
});
}
$('#form').submit(function (){
$('table').attr('hidden',false);
baseURL = $('#url').val();
$('thead').empty();
scanPage($('#url').val());
return false;
});
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
</script>
</body>
</html>
Мой php файл:
<?php
session_start();
require_once __DIR__ . '/Page.php';
$baseURL = $_POST['URL'];
$baseURL = explode('/',$baseURL,4);
$nomPage = $baseURL[3];
$baseURL = $baseURL[0] . "//". $baseURL[2] . '/';
$data = new stdClass();
$data->success = true;
$result = showLinks($baseURL,$nomPage);
if ($result === false){
$data->success = false;
}
else {
$data->page = $result;
$data->links = $_SESSION['visitedLinks'];
}
echo json_encode($data);
function showLinks($baseURL,$nomPage = "") {
if (!array_search($baseURL.$nomPage,$_SESSION['visitedLinks'])){
$result = fread_url($baseURL.$nomPage);
$var = $result[1];
$code = curl_getinfo($result[0], CURLINFO_HTTP_CODE);
$title = get_html_title($var);
array_push($_SESSION['visitedLinks'],$baseURL.$nomPage);
$page = new Page($baseURL . $nomPage, $title, $code);
preg_match_all("/a[\s]+[^>]*?href[\s]?=[\s\"\']+" .
"(.*?)[\"\']+.*?>" . "([^<]+|.*?)?<\/a>/",
$var, $matches);
$matches = $matches[1];
foreach ($matches as $var1) {
if (strlen($var1) >= 1) {
// si il ne s'agit pas d'une référence sur place ou à la racine
if ($var1[0] !== "#" && $var1 !== "/" && $var[0] !== "." && $var[0] !== "?" && $var[0] !== "%") {
// Si le dernier caractère n'est pas un /, l'ajouter
if ($var1[strlen($var1) - 1] !== "/") {
$var1[strlen($var1)] = "/";
}
// Si il s'agit d'un chemin absolu
if ($var1[0] === '/') {
$var1 = ltrim($var1, $var1[0]);
$page->addChild($baseURL . $var1);
} // Si il s'agit d'un chemin relatif
else if (strpos($var1, "http://") === false && strpos($var1, 'https://') === false && strpos($var1, 'www.') === false) {
$page->addChild($baseURL . $nomPage . $var1);
} // Sinon, si il s'agit d'une url
else {
$page->addChild($var1);
}
}
}
}
return $page;
}
else return false;
}
function fread_url($url,$ref="") {
$user_agent = "Mozilla/4.0 (compatible; MSIE 5.01; ".
"Windows NT 5.0)";
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt( $ch, CURLOPT_HTTPGET, 1 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION , 1 );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION , 1 );
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_REFERER, $ref );
curl_setopt ($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
$html = curl_exec($ch);
return [$ch,$html];
}
function get_html_title($html){
preg_match("/\<title.*\>(.*)\<\/title\>/isU", $html, $matches);
return $matches[1];
}
И, наконец, мой класс Page
<?php
class Page implements JsonSerializable {
private $url;
private $titre;
private $code;
private $pages = array();
public function __construct($url,$titre,$code) {
$this->titre = $titre;
$this->url = $url;
$this->code = $code;
}
public function addChild ($child){
array_push($this->pages,$child);
}
/**
* Specify data which should be serialized to JSON
* @link https://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize(){
return [
'url' => $this->url,
'titre' => $this->titre,
'code' => $this->code,
'pages' => $this->pages
];
}
}
На самом деле, это работает на Firefox, но использует много ресурсов. Кроме того, в Chrome через некоторое время на больших сайтах я получаю ERR_INSUFFICIENT_RESOURCES
на консоли.
Итак, я спрашиваю вас, есть ли лучший способ оптимизировать мой код?
Спасибо за вашу помощь.