#php #curl #web-scraping #explode #strstr
#php #curl #очистка веб-страниц #взорваться #strstr
Вопрос:
Я хочу ввести очень длинный список URL-адресов и выполнить поиск определенных строк в исходном коде, выводя список URL-адресов, содержащих строку. Звучит достаточно просто, не так ли? Я разработал приведенный ниже код, входным сигналом которого является html-форма. Вы можете попробовать это на pelican-cement.com/findfrog .
Кажется, что это работает в половине случаев, но сбивается несколькими URL-адресами в разных порядках. При поиске ‘adsense’ он правильно идентифицирует politics1.com из
cnn.com
politics1.com
однако, если перевернуть вывод, он будет пустым. Как я могу получить надежные, непротиворечивые результаты? предпочтительно что-то, во что я мог бы ввести тысячи URL-адресов?
<html>
<body>
<?
set_time_limit (0);
$urls=explode("n", $_POST['url']);
$allurls=count($urls);
for ( $counter = 0; $counter <= $allurls; $counter ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$urls[$counter]);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'GET');
curl_setopt ($ch, CURLOPT_HEADER, 1);
curl_exec ($ch);
$curl_scraped_page=curl_exec($ch);
$haystack=strtolower($curl_scraped_page);
$needle=$_POST['proxy'];
if (strlen(strstr($haystack,$needle))>0) {
echo $urls[$counter];
echo "<br/>";
curl_close($ch);
}
}
//$FileNameSQL = "/googleresearch" . abs(rand(0,1000000000000000)) . ".csv";
//$query = "SELECT * FROM happyturtle INTO OUTFILE '$FileNameSQL' FIELDS TERMINATED BY ','";
//$result = mysql_query($query) or die(mysql_error());
//exit;
echo '$FileNameSQL';
?>
</body>
</html>
Ответ №1:
Немного реорганизовал ваш код. Основным виновником были пробелы. Вам нужно обрезать строку URL перед ее использованием (т.Е. trim($url);
).
Другие изменения:
- Установите поисковый запрос вне цикла for, поскольку он никогда не меняется.
- Настройте объект curl вне цикла и повторно используйте его, просто изменяя URL каждый раз.
- Используйте curl_setopt_array(), чтобы задать несколько параметров curl в одном операторе.
- Используйте цикл foreach, поскольку вы все равно выполняете итерацию по всему массиву, и код становится чище.
- Использование stripos() более эффективно, чем strstr(), и в любом случае не чувствительно к регистру.
- Используйте компаратор !==, чтобы предотвратить подразумеваемое приведение к типу (FALSE !== 0, но FALSE == 0).
- Проверьте возвращаемую строку $ html, поскольку curl_exec() может вернуть FALSE в случае сбоя.
- Закройте объект curl в конце (т. Е. также за пределами оператора if).
Приведенный ниже код можно запустить на моем быстром макете.
<html>
<body>
<form action="search.php" method="post">
URLs: <br/>
<textarea rows="20" cols="50" input type="text" name="url" /></textarea><br/>
Search Term: <br/>
<textarea rows="20" cols="50" input type="text" name="proxy" /></textarea><br/>
<input type="submit" />
</form>
<?
if(isset($_POST['url'])) {
set_time_limit (0);
$urls = explode("n", $_POST['url']);
$term = $_POST['proxy'];
$options = array( CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HEADER => 1,
);
$ch = curl_init();
curl_setopt_array($ch, $options);
foreach ($urls as $url) {
curl_setopt($ch, CURLOPT_URL, trim($url));
$html = curl_exec($ch);
if ($html !== FALSE amp;amp; stristr($html, $term) !== FALSE) { // Found!
echo $url;
}
}
curl_close($ch);
}
?>
</body>
</html>
Комментарии:
1. Спасибо! Проблема сейчас в том, что время ожидания истекает всякий раз, когда вводится более 50 URL-адресов. @Джеймс Ан
2. Обертывание кода в пакетном процессе на PHP намного сложнее. Вместо немедленной обработки отправки формы вам нужно будет записать поисковый запрос и все URL-адреса в файл или базу данных. Затем вызовите другой PHP-файл, который будет обрабатывать вплоть до истечения времени ожидания, сохраняя результаты в файле или базе данных, и верните HTML-файл, который покажет ход выполнения и автоматически (обновит) вызовет пакетный PHP-файл снова, пока не будут обработаны все URL-адреса.
Ответ №2:
Возможно, вам следует вызвать
curl_close($ch);
Независимо от того, находит ли он строку на очищенной странице или нет. Помимо этого я не вижу ничего явно неправильного в коде.
Если чего-то нет в коде, то, вероятно, это какая-то разница в очищенной странице. Возможно, страница динамична и не всегда содержит слово needle при последующих проверках. Возможно, сервер страницы, которую вы пытались очистить, вернул код ошибки.
Ответ №3:
Пара настроек, не уверен, помогут ли они, но все же
$url_to_go = trim($urls[$counter]);
if($url_to_go){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url_to_go);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'GET');
curl_setopt ($ch, CURLOPT_HEADER, 1);
$curl_scraped_page=curl_exec($ch);
curl_close($ch);
// more code follows
}
Ответ №4:
Может ли это быть возврат каретки / пробел вокруг URL-адресов, который отключает его? Возможно, стоило бы поместить в
$urls[$counter] = trim($urls[$counter]);
в начале вашего цикла for.
Также:
if (strpos($haystack, $needle) !== false) {
[...]
}
это более эффективный способ проверки, содержит ли одна строка другую. Вы также могли бы использовать stripos здесь вместо strtolower(), сначала обработав все это (не уверен, улучшит ли это ситуацию).