Sprawdzanie czy adres URL rzeczywiscie istnieje

0

Witam problem jest takiej natury: mam w bazie danych ok 5000-6000 linków. Muszę sprawdzić, które z tych linków są aktywne. Próbowałem zacząć kombinować coś z curlem ale działa on wolno. Sprawdzałem kod błędu ale przez minutę nie byłem w stanie przerobić nawet 100 stron. Przy 6MB łączu :/. Czyli to na pewno problem z wydajnością funkcji curl a nie z tempem ściągania witryn. Czy istnieje jakaś inna metoda aby sprawdzić czy linki są aktywne? Z góry dzięki za podpowiedź.

Pozdrawiam

0

Musisz sie liczyc, ze takie zadanie troche potrwa.

curl nie jest wolny. Pokaz kod, jak to robisz. Ustaw mniejszy time out. Jezeli serwer nie odpowie - np. w przeciagu 5 sekund, oznajemy, ze taki URL nie istnieje. Jezeli serwer odpowiedzial, sprawdzasz, czy zwrocil kod 404, czy 200 i przechodzisz dalej.

1

Na pewno tryb pobierania typu only headers, na pewno warto też ustawić timeout i użyć asynchronicznego multicurla, aby sprawdzało kilka stron jednocześnie.

0
 function GenerujRaport($flaga)
{
  $t = time();

  $result = $this->mDcRaport->GetAll();

  $p = fopen(FILE_DIR.'raport.txt', 'w');
		
  $i = 0;
  $curl = curl_init();
  while ($r = mysql_fetch_array($result))
  {
    if ($flaga & 1 == 1)
    {
	curl_setopt($curl, CURLOPT_URL, $r['link']);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl, CURLOPT_TIMEOUT, 2);
	$rob = curl_exec($curl);
	if (curl_errno($curl) != 0)
	{
          fwrite($p, "$r[issn] $r[tytul] $r[link]\r\n");
	}
	//echo curl_errno($curl)."<br></br>";
    }
    $i++;
  }
  curl_close($curl);

  fclose($p);
  $t = time() - $t;
  return date("s", $t);
}
0

Cienko bardzo, szczególnie że chcesz returntransfer, a w ogóle nic nie robisz z $rob.

Na pewno tryb pobierania typu only headers, na pewno warto też ustawić timeout i użyć asynchronicznego multicurla, aby sprawdzało kilka stron jednocześnie.

W ten sposób wszystko może się wykonać nawet 6 razy szybciej, zakładając że sprawdzasz po 5 stron jednocześnie.

0
Demonical Monk napisał(a)

Cienko bardzo, szczególnie że chcesz returntransfer

Nie chce ale nie wiem jak mogę się tego pozbyć "curl_exec" to wykonanie curla. Przynajmniej ja tak to rozumiem. Pierwszy raz używam tej funkcji :/ Jeżeli nie użyje "returntransfer" to wywala mi treść do przeglądarki zgodnie ze swoim działaniem a to mi jeszcze bardziej nie na rękę :(

0

Nie chodzi o wywalanie curl_exec tylko o żeby wykonać request metodą HEAD, pobierając same nagłówki. Nie musisz koniecznie jechać cURLem, można na socketac (fsockopen).

0

Heh mam tak. Czy chodzi ci o tą linię?:

curl_setopt($curl, CURLOPT_NOBODY, true);

że nie pobieram body strony? W gruncie rzeczy to właśnie działa tak jak chcę ale w tempie ok 1 strony na sec :/ Heh spadam dalej coś szukać. Dzięki za odpowiedzi.

Pozdrawiam

function GenerujRaport()
	{
		$t = time();
		
		$result = $this->mDcRaport->GetAll();

		$p = fopen(FILE_DIR.'raport.txt', 'w');
		
		$i = 0;
		$curl = curl_init();
		while ($r = mysql_fetch_array($result))
		{
			curl_setopt($curl, CURLOPT_URL, $r['link']);
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl, CURLOPT_NOBODY, true);
			
			curl_exec($curl);
			$info = curl_getinfo($curl);
			if ($info['http_code'] >= 300)
			{
				//$r[issn] $r[tytul]
				fwrite($p, $info['http_code'].": $r[link]\r\n");
			}
			
			$i++;
			if ((time() - $t) > 10)
				break;
		}
		curl_close($curl);

		echo $i."<br>";
		
		fclose($p);
		$t = time() - $t;
		return date("s", $t);
	}
0

Jedna strona na sekundę, to wręcz prześwietnie. Szybszego rozwiązania nie znajdziesz, to ZAWSZE zajmie trochę czasu. Rozważ wrzucenie tego jako zadania crona.

0

Mówisz poważnie, że to dobry wynik? Wynika z tego, że będę musiał zapuszczać skrypt na 1,5h żeby mi wszystko przetworzył :/ Wiedziałem, że to trochę potrwa ale myślałem, że w godzince się zmieszczę. No nic chyba mówi się trudno. Dzięki jeszcze raz za zainteresowanie.

Pozdrawiam

EDIT: Jak się orientujesz to powiedz mi jeszcze gdzie tu się znajduję wąskie gardło? W szybkości działania curl, szybkości kompa czy łączu?

0

To ewidentnie jest dobry wynik. Wyobraź sobie że wchodząc w ten temat generujesz wiadomość tekstową typu:

Host	4programmers.net/Forum
User-Agent	Mozilla/5.0 (Windows) Firefox/3
Accept	text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language	pl,en-us;q=0.7,en;q=0.3
Accept-Encoding	gzip,deflate
Accept-Charset	ISO-8859-2,utf-8;q=0.7,*;q=0.7
Keep-Alive	115
Connection	keep-alive
Referer	http://4programmers.net/Forum/Webmastering
Cookie	tracking=a%3A1%3A%7Bs%3A4%3A%224%22%3Bs%3A6%3A%22ldiuy7%22%3D%9D; data=a%3A2%3A%7Bs%3A7%3A%22user_id%22%3Bs%3A5%3A%2227635%22%3Bs%3A3%3A%22key%22%3Bs%3A32%3A%7d70663568cac5af684503681e3a4d41%22%3B%7D; sid=7d70663568cac5af684503681e3a4d41; temp=rdne7nedv4faadlhvscvsr1g37; solr=a%3D3%3A%7Bs%3A4%3A%22t%22%3Bs%3A1%3A%22c%22%3Bs%3A1%3B%24d%22%3Bs%3A1%3A%22a%22%3Bs%3A1%3A%22s%21%3Bs%3A1%3A%22d%22%3B%GD
Cache-Control	max-age=0

I wysyłasz to do Amsterdamu, a potem jeszcze musi przyjść odpowiedź w postaci takiej samej wiadomości (bo olewamy body, więc tylko nagłówki odpowiedzi i zapytania). Mimo że mamy teoretycznie szybkie łącza to trochę są obciążone, przetworzenie requestu przez serwer potrafi zająć 90% czasu wczytywania strony, szczególnie jeśli jest "zatkany". Sekunda to dobry wynik :)

Jeśli interesuje cię głębokie debugowanie problemu, to postaw sobie własny Apache i zmierz np. Firebugiem (addons.mozilla.org) ile trwa wczytanie strony serwowanej przez twój komputer, twojemu komputerowi. Wyjdzie jakieś pół sekundy. Wliczając obciążenie serwera i przestoje na łączu, sekunda to dobrze.

0
Demonical Monk napisał(a)

...użyć asynchronicznego multicurla, aby sprawdzało kilka stron jednocześnie.

Jesteś geniuszem. Pomyślałem, że sprawdzę jeszcze to. Trochę czasu z manualem i wynik:

Czas generowania raportu dla 1000 linków: 23s
:D. Czas się waha to raz krócej a raz dłużej. Pewnie zależy od czasu odpowiedzi serwerów to co mówiłeś. Ale i tak wynik jest świetny :) Dzięki stary sam bym na to nie wpadł. Tylko jak dałem na raz wszystkie 5000 to wtedy jakoś strasznie czas wzrósł, to zrobię po prostu w pętli po 1000. Jeszcze raz dzięki. Rządzisz :) Tutaj dam mój przykład na 1000 wyników może się komuś przyda:

function GenerujRaport()
	{
		set_time_limit(0);
		$t = time();
		
		$result = $this->mDcRaport->GetAll();

		$p = fopen(FILE_DIR.'raport.txt', 'w');
		
		$i = 0;
		
        $tab = array();
        $tab_l = array();

		while (($r = mysql_fetch_array($result))&&($i < 1000))
		{
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $r['link']);
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl, CURLOPT_NOBODY, true);
            
            array_push($tab_l,$r['link']);
			array_push($tab,$curl);
			$i++;
        }

        $mh = curl_multi_init();
        foreach($tab as $k => $h) 
			curl_multi_add_handle($mh,$h);

        $running = null;
        do
        {
			curl_multi_exec($mh,$running);
        }
        while($running > 0);

        $i = 0;
        $ind = 1;
        foreach($tab as $k => $h)
        {
			$info = curl_getinfo($h);
			if ($info['http_code'] >= 400)
			{
				fwrite($p, $ind." ".$info['http_code'].": $tab_i[$i] $tab_l[$i]\r\n");
				$ind++;
			}
			curl_multi_remove_handle($mh,$h);
			$i++;
        }
        curl_multi_close($mh); 

		echo $i."<br>";
		
		fclose($p);
		$t = time() - $t;
		return date("s", $t);
	}

Pozdrawiam

0

Dobra teraz jest inny problem. Przy powyższym kodzie fajnie bo przetwarza strony w ekstra tempie ale

$info['http_code']

zwraca bardzo często 0 czyli false :/ Może ktoś wie dlaczego tak się dzieje.

Pozdrawiam

0

Ale kiedy zwraca zero? Mimo że strona dalej działa, mimo że nie działa czy losowo?

0

Opisze dokładniej. Sprawdziłem ten kod na pewno przetwarza wszystkie strony to plus. Ale zasada jest taka, że czym więcej stron chce przetworzyć za jednym wykonaniem skryptu tym mniej dokładne są wyniki. Definiując mniej dokładne wyniki :) - albo zwraca 0 (całkowicie losowo, czasem strona jest czasem nie ma) albo potrafi zwrócić 400 jak strona powinna zwrócić normalne 200 czyli OK :/ I jest to losowo w sensie takim, że wyniki się różnią między wywołaniami. Raz jedne a raz inne strony są rozpoznane dobrze. W każdym razie czym więcej tym gorzej.

Pozdrawiam

EDIT: Zrobienie na kilka razy czyli w pętli po mniejszej ilości linków też nic nie daje :/ Więcej linków przerabianych za jednym razem w skrypcie = gorzej rozpoznane.

0

Może jakiś błąd w cURLu, ale imo powaliłeś coś w tym kodzie z obsługą asynchroniki.

0
Demonical Monk napisał(a)

...ale imo powaliłeś coś w tym kodzie z obsługą asynchroniki.

Skorzystałem teraz z tej oto gotowej klasy do obsługi cURL'a:
http://semlabs.co.uk/journal/object-oriented-curl-class-with-multi-threading
i jest to samo więc raczej nic nie powaliłem :)

Pozdrawiam

0

Rozwiązałem problem jednak poprzez pętlę. Mało elegancko ale skończyły mi się pomysły a działać musiało :p Tutaj kod, może się komuś przyda:

function GenerujRaport()
	{
		set_time_limit(0);
		$t = time();

		$p = fopen(FILE_DIR.'raport.txt', 'w');
		fclose($p);

		$this->mDcRaport->Inicjalizacja();
		
		$result = $this->mDcRaport->GetAll();
		
		while (mysql_num_rows($result) > 1)
		{
			while($r = mysql_fetch_array($result))
			{
				$curl = new CURL();
				$opts = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_NOBODY => true, CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
			
				$i = 0;
				$tab = Array();
				while ($r = mysql_fetch_array($result))
				{
					$curl->addSession($r['link'], $opts );
					array_push($tab, $r['id']);
					$i++;
				}
			 
				$c = $curl->exec();
				$info = $curl->info();
			
				foreach($info as $ind => $i)
				{
					if (empty($i['http_code']))
					{
						$this->mDcRaport->UstawHttp($tab[$ind], 0);
					}
					else
					{
						$this->mDcRaport->UstawHttp($tab[$ind], $i['http_code']);
					}
				}
	
				$curl->clear();		
			}
			$result = $this->mDcRaport->GetAll();
		}

		$p = fopen(FILE_DIR.'raport.txt', 'a');	
		$result = $this->mDcRaport->GetResult();
		
		$i = 0;
		while ($r = mysql_fetch_array($result))
		{
			$i++;
			fwrite($p, "$i. $r[http] $r[issn] $r[tytul] $r[link]\r\n");
		}
		
		fclose($p);

		$t = time() - $t;
		return date("i s", $t);
	}

Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1