Новостные сайты являются хорошим источником данных для обработки моделями машинного обучения. При этом, большинство новостных web-ресурсов перегружено различной «лишней» информацией, не относящейся к сути статей, будь то навязчивая реклама, всплывающие окна со служебной информацией и т.д. Очистка статей при выгрузке с web-ресурсов от «шума» помогла бы снизить количество ошибок обработки данных.
В этой статье мы рассмотрим создание инструмента, с помощью которого можно получать читабельный текст из статей с минимальной «лишней» информацией.
Чтобы написать Ваш собственный граббер самостоятельно, Вам потребуются знания в области Web-разработки, такие как понимание языка гипертекстовой разметки HTML (понимание значений тегов, размещение информации внутри них) и основной информации о структуре DOM-дерева при отрисовке сайтов, а также базовые навыки программирования на языке Python.
Итак, начнем.
Для работы нам потребуются библиотеки:
- request
- BeautifulSoup
Библиотека requests по факту является стандартом при работе с составлением HTTP-запросов к web-ресурсам. В этой библиотеке собрано множество методов, с помощью которых значительно упрощается процесс создания запросов и разбора ответов от сервера. И это помогает нам сосредоточиться на написании непосредственно нашего алгоритма, а не на поиске способов обеспечить стабильную связь и получение данных с web-ресурсов.
В нашем скрипте будем использовать получение данных при помощи HTTP-метода GET. Метод GET является инструкцией web-ресурсу о том, что с него запрашиваются некоторые данные, указанные как параметр к GET. Чтобы выполнить такой запрос, используя библиотеку requests, достаточно ввести requests.get (< URL >; <дополнительные параметры>). При существовании URL и при наличии прав на доступ к ресурсу, в ответ придут данные HTML-страницы, которые уже можно обработать различными инструментами языка Python. Натболее распространенным инструментом для данной задачи является библиотека BeautifulSoup.
Библиотека BeautifulSoup используется для анализа документов HTML и XML. Она создает дерево синтаксического анализа для полученных страниц (DOM-дерево), которое можно использовать для извлечения данных из HTML в удобные для обработки на языке Python конструкции (словари, списки, строки), что полезно для очистки веб-страниц от ненужной информации.
Алгоритм работы нашей программы будет заключаться в том, что при запуске скрипта Python из командной строки и с указанием URL требуемой нам статьи в качестве параметра, мы будем получать HTML-страницу при помощи метода get библиотеки request. Затем создаем объект BeautifulSoup, который непосредственно и помогает нам очистить статью от лишней информации.
Но для того, чтобы обозначить, что именно считать лишней информацией, а что полезной, нам необходимо проанализировать источник, из которого мы будем брать статьи. Сейчас распространенной практикой является разработка web-ресурсов в блочном формате. Все данные, которые необходимо разместить на страницах разбиваются по логическим блокам и помещаются в теги < div > < /div >
Далее, уже внутри этих блоков информация может принимать различные вариации в зависимости от назначения. В блоках, предназначенных для навигации преобладают ссылочные теги, в блоках, где имеется много изображений, соответственно, много тегов. Нас же интересуют блоки web-страниц, в которых хранятся тексты статей.
Если провести небольшое исследование размещения информации на новостных сайтах, то почти на каждом мы увидим, что блоки с непосредственно самой статьей изобилуют тегами < p > < /p >
Поэтому, первым логичным шагом для создания нашего простого граббера будет взять за основу именно тег < p > < /p >
В дальнейшем, Вы можете самостоятельно проанализировать необходимые источники и уточнить в настройках скрипта, какие теги будут браться для обработки.
Чтобы наш код можно было удобно переиспользовать в других проектах и подключать файл скрипта в другие скрипты Python — первым делом напишем класс, в котором будем хранить все нужные нам методы и объекты.
class GrabberArticle:
url = «»
filename = «»
path = «»
content_tags = [‘p’]
wrap = 80
Описание объектов:
url – URL статьи, которую хотим обработать.
filename – имя файла для сохранения. Соответствует последнему элементу в URL. Например, для host.net/path1/path2 — это path2
path – Путь для сохранения обработанного текста. Соответствует ([Каталог с файлом скрипта]/host.net/path1/path2/…)
content_tags – HTML-теги для обработки. По умолчанию установлен тег
, так как мы приняли его за основной тег, в котором наиболее часто размещён основной полезный контент статьи.
wrap – количество символов в строке очищенного текста. По умолчанию установлено значение в 80 символов — негласное правило читаемости текста на экране.
Давайте теперь напишем главный метод для нашего класса GrabberArticle, который будет получать ответ от web-ресурса и при помощи BeautifulSoup отфильтровывать только нужные нам данные:
def get_text(self):
r = requests.get(self.url).text
soup = BeautifulSoup(r, ‘html.parser’)
# найдем все теги по списку self.content_tags
content = soup.find_all(self.content_tags)
wrapped_text = «»
for p in content:
# пропускаем теги без значений
if p.text != »:
# форматирование ссылок в вид [ссылка]
links = p.find_all(‘a’)
if links != »:
for link in links:
p.a.replace_with(link.text + str(«[» + link[‘href’] + «]»))
# устанавливаем ширину строки равной self.wrap (по умолчанию, 80 символов)
wrapped_text += ».join(textwrap.fill(p.text, self.wrap)) + «nn»
self.write_in_file(wrapped_text)
В качестве результата будем выводить текстовый файл, который будет называться по имени последнего элемента URL- адреса. Также создадим иерархию для размещения этого файла в файловой системе, исходя из оставшихся элементов URL-адреса. Например, для URL: https://lenta.ru/news/2020/04/09/centenarian: файл будет сохранен под именем centenarian.txt в каталоге [Директория со скриптом]/lenta.ru/news/2020/04/09/. Такая иерархия на первый взгляд может выглядеть избыточной. Но такой подход может быть полезен, если с одного и того же источника (и тем более нескольких) будет выгружаться большое количество статей. В такой структуре данные будет легко сгруппировать по определенным признакам. Это позволит гораздо проще обращаться к массиву данных из статей, если, например, они будут использованы для проведения тематических исследований с помощью моделей машинного обучения.
def __init__(self, url_address):
self.url = url_address
# Get path and filename for saving article by splitting URL.
# If the URL ends with some.html, then the previous (-2) element
# of the path is taken to form the path and the filename = some.html.txt respectively.
path_arr = self.url.split(‘/’)
if path_arr[-1] != »:
self.filename = path_arr[-1] + «.txt»
self.path = os.getcwd() + «/».join(path_arr[1:-1])
else:
self.filename = path_arr[-2] + «.txt»
self.path = os.getcwd() + «/».join(path_arr[1:-2])
if not os.path.exists(self.path):
os.makedirs(self.path)
Допишем метод, который будет записывать в файл полученный «чистый» текст:
def write_in_file(self, text):
# записывает text в каталог self.path:»[CUR_DIR]/host.ru/path_item1/path_item2/…»
file = open(str(self.path) + ‘/’ + str(self.filename), mode=»a»)
file.write(text)
file.close()
Готово! Теперь наш скрипт можно запускать из командной строки, просто передавая ему URL статьи:
Наш скрипт формирует текстовый файл с иерархией, соответствующей URL. Текст в таком формате полностью готов для дальнейшей обработки для задач NLP в машинном обучении. Ну а сама статья стала намного читабельнее без перегрузки лишней информацией.
В дальнейшем данный скрипт можно усовершенствовать так, чтобы он в качестве входных данных использовал файл со списком URL и выгружал уже готовый массив данных целиком. А для написания более детального скрипта выгрузки для Ваших источников необходимо просто дописать нужные теги в объект GrabberArticle.content_tags, либо передавать их через отдельный файл настроек.
Примечание:
Несмотря на то, что грабберы являются очень полезным инструментом по созданию выборок для проведения исследований, машинная выгрузка данных с web-ресурсов приводит к значительному повышению сетевой нагрузки на сайты и доставляет проблемы владельцам ресурсов. Некоторые даже блокируют ip-адреса, с которых замечена подобная активность. Поэтому призываю пользоваться грабберами в пределах разумного и не перегружать удаленные web-ресурсы, чтобы не вызывать негативных последствий на них.
Пишем граббер на PHP
Грабберами в народе называют серверные скрипты, предназначенные для получения данных с
различных серверов и встраивания их в свои страницы. В инете есть куча примеров RSS-грабберов,
извлекающих тексты с новостных лент, но мне лично нужен не какой-то RSS, которым
я ни разу в жизни не пользовался, а полноценный скрипт, который легко настроить для
извлечения любой нужной мне информации с любой из доступных в сети страниц.
Так что эта небольшая статья — как раз пример написания граббера на языке PHP.
Задача состоит, собственно, из 3 этапов.
1. Получение данных с нужного нам URL
Для этого в PHP существует несколько возможностей:
Стандартная функция fopen, служащая для открытия файла
Применять ее не очень удобно, так как нельзя контролировать время соединения, получать ответы
ошибок сервера и т.д. Кроме того, она может быть запрещена на хостинге через http.
Тем не менее, вот пример откуда-то. Здесь мы парсим выдачу популярного сайта bash.org:
<? $url='http://www.bash.org.ru/best'; $file = @fopen ($url, 'r'); if ($file==false) print '<p>Не могу открыть сайт '.$url.'!'; else { $contents = fread ($file, 100000); $contents = preg_match_all('|<div>(.+)</div>|U',$contents,$frazes); for($i=0;$i<5;$i++){ if ($i<>5) echo "<hr>".$frazes[1][$i]."rn<hr>"; } fclose ($file); } ?>
Популярный вариант этого же подхода еще проще —
<? $file = file_get_contents('http://www.bash.org.ru/best'); $file = preg_match_all('|<div>(.+)</div>|U',$file,$frazes); for($i=0;$i<11;$i++){ if ($i<>5) echo "<hr>".$frazes[1][$i]."rn<hr>"; } ?>
$str=file_get_contents(”http://google.com/”);
(по сути, file_get_contents — это fopen, fread, fclose одной командой)
Библиотека cURL
Удобнее, но также может быть не установлена или запрещена на хостинге.
Соединение через сокеты
Именно его мы используем, чтоб
HTTP-заголовок формировался полностью под нашим контролем.
Полноценно проверять коды ошибок в учебной статье не будем, не надейтесь, но
все же скрипт должен получиться похожим на человеческий.
Следующая функция получает содержимое, расположенное на хосте $host по абслютному
пути $path. Имя хоста не включает в себя префиксов http://www, путь начинается с символа
корневого каталога /.
function get_URL_by_socket ($host,$path) { //Получает URL $path с хоста $host через сокеты. $fp = fsockopen($host, 80); if (!$fp) { die ("Не могу получить данные с url http://$host/$path"); } else { $out = "GET $path HTTP/1.0rn"; $out .= "Accept: image/gif, application/xhtml+xml, */*rn"; $out .= "Accept-Language: rurn"; $out .= "Host: $hostrn"; //Имитируем браузер Opera Mini: $out .= "User-Agent: Opera/8.01 (J2ME/MIDP; ". "Opera Mini/2.0.4509/1716; ru; U; ssr)rn"; $out .= "Cache-Control: no-cachern"; //Не кэшировать $out .= "Connection: Closernrn"; fwrite($fp, $out); $headers = ""; while ($str = trim(fgets($fp))) $headers .= "$strn"; $body = ""; while (!feof($fp)) $body .= fgets($fp); fclose($fp); } return $body; }
2. Извлечение содержимого из страницы
На следующем этапе мы должны извлечь из кода страницы, полученного функцией
get_URL_by_socket, полезную для нас часть. Для этой цели в PHP существют регулярные выражения
(ссылка на статью внизу страницы) и строковые функции. Я для простоты взял здесь случай,
когда мы можем выделить в коде страницы куски текста, однозначно ограничивающие нужную
нам часть снизу ($end) и сверху ($start). В принципе, при внимательном анализе исходного кода
любой страницы
(в браузере обратитесь к меню Вид, пункту «Исходный текст» или «Источник») легко выделить
такие куски. Так как мы будем писать их внутрь строковых переменных, ограниченных
двойными кавычками, то если в тексте строки встречается двойная кавычка «, ее нужно заменить
на сочетание символов «, как здесь:
$start="<div class="temper">";
Всю информацию будет обрабатывать следующая функция:
function process($s,$start,$end,$include) { //Парсит полученный файл - здесь-то и пишется главное //У нас это извлечение содержимого от $start до $end $s1=strpos ($s,$start); $s2=strpos ($s,$end); if (!is_integer($s1)) { return "Не найден начальный сегмент: ".htmlspecialchars($start); } if (!is_integer($s2)) { return "Не найден конечный сегмент: ".htmlspecialchars($end); } if ($s1>$s2) { return "Конечный сегмент предшествует начальному"; } if ($include) { //Включать начало и конец return substr ($s,$s1,$s2-$s1+strlen($end)); } else { //Исключить начало и конец $s1+=strlen($start); return substr ($s,$s1,$s2-$s1); } }
Параметр $include должен быть равен true, если строки $start и $end надо оставить в выводе
или false, если их надо исключить.
3. Дополнительная обработка и вывод
Строку, возвращенную функцией process, можно дополнительно обработать (например, исключить
лишние стили или ссылки, сделать относительные пути абсолютными и т.п.), либо сразу вывести
ее на экран функцией PHP print или echo. В приведенном ниже примере единственная вызываемая
пользователем парсера функция parser вызывает 2 остальные функции и
дополнительно один раз шлет заголовок с кодировкой документа (если модуль работает из готового
движка, блок с вызовом header нужно убрать).
function parser ($host,$path,$start,$end,$include) { //Основной вызов парсера: //$host, $path - хост без http://www. и путь к файлу, начиная с / //$start, $end - строки начала и конца извлекаемого содержимого //$include - если true, включать в вывод строки $start и $end static $first=true; $s= get_URL_by_socket ($host,$path); if ($first) { //Заголовок посылается только при 1-м вызове $first=false; //Если вызывается из "движка" - можно убрать этот блок header('Content-type:text/html;charset=windows-1251'); } return process($s,$start,$end,$include); }
Вызвать наш парсер можно, например, так:
$host="ngs.ru"; $path="/"; $start="<div class="temper">"; $end="width="30" height="15"></td>n </tr>n</table>"; $include=true; print parser ($host,$path,$start,$end,$include);
Здесь мы вытаскиваем краткий прогноз погоды с новосибирского городского сервера НГС.
Обратите внимание, что все пробелы, которые были в полученном по адресу файле, я сохранил в строке параметра $end, а переносы строк заменил на n
Еще пример:
$s=parser ("pers.narod.ru","/index.html", "<title>","</title>",false); print'<br>'.$s;
Здесь просто берется титул (содержимое тега TITLE) моей домашней странички.
Думаю, на основе этой статьи нетрудно модифицировать граббер под свои задачи.
Скачать и ссылки
Скачать этот пример в одном файле .PHP (ZIP) (1 Кб)
Статья про регулярные выражения PHP — по-моему, одна из лучших
Оригинал статьи
10.02.2009, 14:03 [20538 просмотров]
К этой статье пока нет комментариев, Ваш будет первым
<?php
/*
Любой граббер для удобства можно разделить на ТРИ оcновных части-этапа:
-получение
-обработка
-выдача
Получение.
Для того, что бы граббер нормально функционировал необходимо написать функцию для получнения
страницы с удаленного хоста по заданному url, надежнее пользоваться сокетами
(потому что библиотека CURL установлена не везде и не всегда, использовать file_get_contents()
и комбинации implode(»,file(..)) конечно тоже можно, просто сокет предоставляет побольше возможностей.
Напишем функцию получния страницы по урл.
*/
function data($path,$host)
{
/*
$path путь к файлу скрипта, а так же передаваемые параметры
$host сграббливаемый хост (например, sasisa.ru)
*/
$fp = fsockopen($host, 80);
if (!$fp)
{
die(‘ошибка’);
}
else
{
$out = «GET $path HTTP/1.0rn»;
$out .= «Accept: image/gif, application/xhtml+xml, */*rn»;
$out .= «Accept-Language: rurn»;
$out .= «Host: $hostrn»;
//прикинемся оперой-мини
$out .= «User-Agent: Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1716; ru; U; ssr)rn»;
$out .= «Cache-Control: no-cachern»;
$out .= «Connection: Closernrn»;
fwrite($fp, $out);
$headers = «»;
while ($str = trim(fgets($fp)))
$headers .= «$strn»;
$body = «»;
while (!feof($fp))
$body .= fgets($fp);
fclose($fp);
}
//возвращаем данные
return $body;
}
/*
Итак, функция для получения страницы готова, теперь составим функцию для обработки данных, тоесть для
выреза рекламы, подмены ссылок итп
*/
/*
function process($s)
{
Здесь сложно дать какие-то рекоммендации, все «грабберописание» состоит в основном в
придумывании этой функции, сделаем пока что «заглушку» на этом месте
return $s;
}
*/
/*
Для корректной работы грабба необходимо теперь правильно определять переменную $path, для примера давайте граббить
всем известный http://wen.ru/forum/index.php
пример очень характерный, потому что многие «потенциальные жертвы» грабов (загруз центры например)
состоят как раз из одного файла
*/
//с хостом определились
$host=’wen.ru’;
if (empty($_SERVER[‘QUERY_STRING’]))
{
//начальная позиция
$path=’/forum/index.php’;
}
else
{
//новые параметры
$path=’/forum/?’.$_SERVER[‘QUERY_STRING’];
}
/*
теперь необходимо зайти на страницу форума и посмотреть ее в коде
видно что ссылки выдаются так
<a href=»/forum/?p=1&f=1&w=htm»>Общение</a>
для работы грабба достаточно изменить ссылку так
<a href=»index.php?p=1&f=1&w=htm»>Общение</a>
что и сделаем в функции process
*/
/*function process($s)
{
$s=str_replace(‘<a href=»/forum/’,'<a href=»index.php’,$s);
return $s;
}*/
//можно в принципе запускать (ПЕРВЫЙ ЭТАП)
$s=data($path,$host);
//обрабатываем (ВТОРОЙ ЭТАП)
$s=process($s);
//выдаем результат (ТРЕТИЙ ЭТАП)
/*
третий этап не так прост как кажется, если вы граббите загрузки, то
необходимо организовать переадресацию на прямую ссылку с контентом
*/
header(‘Content-type:text/html;charset=utf-8’);
echo $s;
/*
как видим, граббер вполне работает, только не грузятся смайлики,
давайте подкорректируем это и впишем свой копирайт на страницу
*/
function process($s)
{
$s=str_replace(‘<a href=»/forum/’,'<a href=»‘.$_SERVER[‘SCRIPT_NAME’],$s);
//смайлы
$s=str_replace(‘<img src=»‘,'<img src=»http://wen.ru/’,$s);
//копирайт
$s=str_replace(‘</body>’,'<div>(c)snippets</div></body>’,$s);
return $s;
}
/*
разумеется, вы не сможете написать в тему или создать ее, тут надо использовать
POST запросы, задача этой статьи не создание флудер-скрипта а ознакомление с
принципами написания грабберов.
*/
?>
Добавил: TorchWood (14 янв 2009 г., 11:59)
Рейтинг: (2)
Прочитано: 19501
Время прочтения: 6 мин.
Чтобы написать Ваш собственный
граббер самостоятельно, Вам потребуются знания в области Web-разработки, такие как понимание
языка гипертекстовой разметки HTML
(понимание значений тегов, размещение информации внутри них) и основной информации о структуре DOM-дерева при отрисовке
сайтов, а также базовые навыки
программирования на языке Python.
Итак, начнем.
Для работы нам потребуются библиотеки:
- request
- BeautifulSoup
Библиотека requests по
факту является стандартом при работе с составлением HTTP-запросов к web-ресурсам. В этой библиотеке собрано
множество методов, с помощью которых значительно упрощается процесс создания
запросов и разбора ответов от сервера. И это помогает нам сосредоточиться на
написании непосредственно нашего алгоритма, а не на поиске способов обеспечить
стабильную связь и получение данных с web-ресурсов.
В нашем
скрипте будем использовать получение данных при помощи HTTP-метода GET. Метод GET является
инструкцией web-ресурсу
о том, что с него запрашиваются некоторые данные, указанные как параметр к GET. Чтобы выполнить такой
запрос, используя библиотеку requests,
достаточно ввести requests.get (
<URL>; <дополнительные
параметры> ). При существовании URL и при наличии прав на доступ к
ресурсу, в ответ придут данные HTML-страницы,
которые уже можно обработать различными инструментами языка Python. Натболее распространенным
инструментом для данной задачи является библиотека BeautifulSoup.
Библиотека BeautifulSoup
используется для анализа документов HTML и XML. Она создает дерево
синтаксического анализа для полученных страниц (DOM-дерево), которое можно использовать
для извлечения данных из HTML в удобные для обработки на языке Python конструкции
(словари, списки, строки), что полезно для очистки веб-страниц от ненужной
информации.
Алгоритм работы нашей программы будет заключаться в том, что при запуске скрипта Python из командной строки и с указанием URL требуемой нам статьи в качестве параметра, мы будем получать HTML-страницу при помощи метода get библиотеки request. Затем создаем объект BeautifulSoup, который непосредственно и помогает нам очистить статью от лишней информации.
Но для того, чтобы обозначить, что именно считать лишней информацией, а что полезной, нам необходимо проанализировать источник, из которого мы будем брать статьи. Сейчас распространенной практикой является разработка web-ресурсов в блочном формате. Все данные, которые необходимо разместить на страницах разбиваются по логическим блокам и помещаются в теги <div> </div>. Далее, уже внутри этих блоков информация может принимать различные вариации в зависимости от назначения. В блоках, предназначенных для навигации преобладают ссылочные теги <a> </a>, в блоках, где имеется много изображений, соответственно, много тегов <img>. Нас же интересуют блоки web-страниц, в которых хранятся тексты статей.
Если провести
небольшое исследование размещения информации на новостных сайтах, то почти на
каждом мы увидим, что блоки с непосредственно самой статьей изобилуют тегами <p> </p>. Поэтому, первым логичным шагом для создания
нашего простого граббера будет взять за основу именно тег <p> </p>.
В дальнейшем,
Вы можете самостоятельно проанализировать необходимые источники и уточнить в
настройках скрипта, какие теги будут браться для обработки.
Чтобы наш код можно было удобно переиспользовать в других проектах и подключать файл скрипта в другие скрипты Python — первым делом напишем класс, в котором будем хранить все нужные нам методы и объекты.
class GrabberArticle:
url = ""
filename = ""
path = ""
content_tags = ['p']
wrap = 80
Описание объектов:
url
– URL статьи,
которую хотим обработать.
filename –
имя файла для сохранения. Соответствует последнему
элементу в URL. Например,
для host.net/path1/path2 — это path2
path
– Путь для сохранения обработанного текста. Соответствует ([Каталог с файлом
скрипта]/host.net/path1/path2/…)
content_tags – HTML-теги для обработки. По умолчанию установлен тег <p>, так как мы приняли его за основной тег, в котором наиболее часто размещён основной полезный контент статьи.
wrap – количество символов в строке очищенного текста. По умолчанию установлено значение в 80 символов — негласное правило читаемости текста на экране.
Давайте теперь напишем главный метод для нашего класса GrabberArticle, который будет получать ответ от web-ресурса и при помощи BeautifulSoup отфильтровывать только нужные нам данные:
def get_text(self):
r = requests.get(self.url).text
soup = BeautifulSoup(r, 'html.parser')
# найдем все теги по списку self.content_tags
content = soup.find_all(self.content_tags)
wrapped_text = ""
for p in content:
# пропускаем теги без значений
if p.text != '':
# форматирование ссылок в вид [ссылка]
links = p.find_all('a')
if links != '':
for link in links:
p.a.replace_with(link.text + str("[" + link['href'] + "]"))
# устанавливаем ширину строки равной self.wrap (по умолчанию, 80 символов)
wrapped_text += ''.join(textwrap.fill(p.text, self.wrap)) + "nn"
self.write_in_file(wrapped_text)
В качестве результата будем выводить текстовый файл, который будет называться по имени последнего элемента URL- адреса. Также создадим иерархию для размещения этого файла в файловой системе, исходя из оставшихся элементов URL-адреса. Например, для URL: https://lenta.ru/news/2020/04/09/centenarian : файл будет сохранен под именем centenarian.txt в каталоге [Директория со скриптом]/lenta.ru/news/2020/04/09/. Такая иерархия на первый взгляд может выглядеть избыточной. Но такой подход может быть полезен, если с одного и того же источника (и тем более нескольких) будет выгружаться большое количество статей. В такой структуре данные будет легко сгруппировать по определенным признакам. Это позволит гораздо проще обращаться к массиву данных из статей, если, например, они будут использованы для проведения тематических исследований с помощью моделей машинного обучения.
def __init__(self, url_address):
self.url = url_address
# Get path and filename for saving article by splitting URL.
# If the URL ends with some.html, then the previous (-2) element
# of the path is taken to form the path and the filename = some.html.txt respectively.
path_arr = self.url.split('/')
if path_arr[-1] != '':
self.filename = path_arr[-1] + ".txt"
self.path = os.getcwd() + "/".join(path_arr[1:-1])
else:
self.filename = path_arr[-2] + ".txt"
self.path = os.getcwd() + "/".join(path_arr[1:-2])
if not os.path.exists(self.path):
os.makedirs(self.path)
Допишем метод, который будет записывать в файл полученный «чистый» текст:
def write_in_file(self, text):
# записывает text в каталог self.path:"[CUR_DIR]/host.ru/path_item1/path_item2/..."
file = open(str(self.path) + '/' + str(self.filename), mode="a")
file.write(text)
file.close()
Готово! Теперь наш скрипт можно запускать из командной строки, просто передавая ему URL статьи:
>python grabber.py https://lenta.ru/news/2020/04/09/centenarian
Наш скрипт формирует текстовый
файл с иерархией, соответствующей URL. Текст в таком формате полностью готов для дальнейшей
обработки для задач NLP в машинном обучении. Ну а сама статья стала намного
читабельнее без перегрузки лишней информацией.
В дальнейшем данный скрипт можно усовершенствовать так, чтобы он в качестве входных данных использовал файл со списком URL и выгружал уже готовый массив данных целиком. А для написания более детального скрипта выгрузки для Ваших источников необходимо просто дописать нужные теги в объект GrabberArticle.content_tags, либо передавать их через отдельный файл настроек.
Примечание:
Несмотря на то, что грабберы являются очень полезным инструментом по созданию выборок для проведения исследований, машинная выгрузка данных с web-ресурсов приводит к значительному повышению сетевой нагрузки на сайты и доставляет проблемы владельцам ресурсов. Некоторые даже блокируют ip-адреса, с которых замечена подобная активность. Поэтому призываю пользоваться грабберами в пределах разумного и не перегружать удаленные web-ресурсы, чтобы не вызывать негативных последствий на них.
Полный код из статьи размещен по адресу: https://github.com/ZveRuss/GrabberArticle
Как написать граббер
<?php /* *Как написать граббер. *автор: nc_soft *28.09.07 */ /* Любой граббер для удобства можно разделить на ТРИ оcновных части-этапа: -получение -обработка -выдача Получение. Для того, что бы граббер нормально функционировал необходимо написать функцию для получнения страницы с удаленного хоста по заданному url, надежнее пользоваться сокетами (потому что библиотека CURL установлена не везде и не всегда, использовать file_get_contents() и комбинации implode('',file(..)) конечно тоже можно, просто сокет предоставляет побольше возможностей. Напишем функцию получния страницы по урл. */ function data($path,$host) { /* $path путь к файлу скрипта, а так же передаваемые параметры $host сграббливаемый хост (например, sasisa.ru) */ $fp = fsockopen($host, 80); if (!$fp) { die('ошибка'); } else { $out = "GET $path HTTP/1.0rn"; $out .= "Accept: image/gif, application/xhtml+xml, */*rn"; $out .= "Accept-Language: rurn"; $out .= "Host: $hostrn"; //прикинемся оперой-мини $out .= "User-Agent: Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1716; ru; U; ssr)rn"; $out .= "Cache-Control: no-cachern"; $out .= "Connection: Closernrn"; fwrite($fp, $out); $headers = ""; while ($str = trim(fgets($fp))) $headers .= "$strn"; $body = ""; while (!feof($fp)) $body .= fgets($fp); fclose($fp); } //возвращаем данные return $body; } /* Итак, функция для получения страницы готова, теперь составим функцию для обработки данных, тоесть для выреза рекламы, подмены ссылок итп */ /* function process($s) { Здесь сложно дать какие-то рекоммендации, все "грабберописание" состоит в основном в придумывании этой функции, сделаем пока что "заглушку" на этом месте return $s; } */ /* Для корректной работы грабба необходимо теперь правильно определять переменную $path, для примера давайте граббить всем известный http://wen.ru/forum/index.php пример очень характерный, потому что многие "потенциальные жертвы" грабов (загруз центры например) состоят как раз из одного файла */ //с хостом определились $host='wen.ru'; if (empty($_SERVER['QUERY_STRING'])) { //начальная позиция $path='/forum/index.php'; } else { //новые параметры $path='/forum/?'.$_SERVER['QUERY_STRING']; } /* теперь необходимо зайти на страницу форума и посмотреть ее в коде видно что ссылки выдаются так <a href="/forum/?p=1&f=1&w=htm">Общение</a> для работы грабба достаточно изменить ссылку так <a href="index.php?p=1&f=1&w=htm">Общение</a> что и сделаем в функции process */ /*function process($s) { $s=str_replace('<a href="/forum/','<a href="index.php',$s); return $s; }*/ //можно в принципе запускать (ПЕРВЫЙ ЭТАП) $s=data($path,$host); //обрабатываем (ВТОРОЙ ЭТАП) $s=process($s); //выдаем результат (ТРЕТИЙ ЭТАП) /* третий этап не так прост как кажется, если вы граббите загрузки, то необходимо организовать переадресацию на прямую ссылку с контентом */ header('Content-type:text/html;charset=utf-8'); echo $s; /* как видим, граббер вполне работает, только не грузятся смайлики, давайте подкорректируем это и впишем свой копирайт на страницу */ function process($s) { $s=str_replace('<a href="/forum/','<a href="'.$_SERVER['SCRIPT_NAME'],$s); //смайлы $s=str_replace('<img src="','<img src="http://wen.ru/',$s); //копирайт $s=str_replace('</body>','<div>(c)snippets</div></body>',$s); return $s; } /* разумеется, вы не сможете написать в тему или создать ее, тут надо использовать POST запросы, задача этой статьи не создание флудер-скрипта а ознакомление с принципами написания грабберов. */ ?>
URL: https://visavi.net/articles/41
«Грабим» странички
С аудиограбберами знакомы все. Нам предстоит сделать свой собственный граббер информации из Интернета. Нам понадобится подопытный кролик, на роль которого я предлагаю выбрать сайт http://subscribe.ru 🙂 Что мы можем у них стянуть хорошего? Собственно говоря, там хорошего много, но есть кое-что, что нам и нашим посетителям может действительно пригодиться! Я имею в виду список новых рассылок, переведенных в категорию серебряных. Не секрет, что когда рассылку переводят в эту категорию, ее рейтинг (в виде количества подписчиков) непременно взлетает. Вольно или невольно мы будем содействовать этому процессу, так как посетители Вашего сайта смогут подписаться на понравившиеся им рассылки прямо, так сказать, не отходя от кассы. Для начала нам потребуется адрес, откуда мы будем грабить информацию. Он такой — http://win.subscribe.ru/catalog/latest Если кого-то не устроит кодировка, подставьте свою. По указанному адресу мы находим все переведенные в категорию серебряных рассылки. Причем список постоянно обновляется, оставаясь таким образом актуальным всегда.
Привожу весь код, пояснения к нему — дальше…
<? // начало $link = "http://win.subscribe.ru/catalog/latest"; $file = @fopen($link, "r"); if ($file) { $rf = fread($file, 200000); fclose($file); } else { echo "Извините, запрошенная страница временно не доступна!"; } // 1 $rf = trim (chop ($rf)); $s = strpos($rf, " $rf = substr($rf, $s); // 2 $s = strpos($rf, " $rf = substr($rf, 0, $s); // 3 $rf = str_replace ("/catalog/","http://win.subscribe.ru/catalog/", $rf); $rf = str_replace ("/archive/","http://win.subscribe.ru/archive/", $rf); $rf = str_replace ("ACTION=/member/quick","ACTION=http://win.subscribe.ru/member/quick", $rf); $rf = str_replace ("/img/money2.gif","http://win.subscribe.ru/money2.gif", $rf); $rf = str_replace ("/img/a114.gif","http://win.subscribe.ru/af.gif", $rf); $rf = str_replace ("/img/af.gif","http://win.subscribe.ru/af.gif", $rf); // 4 echo $rf; ?>
А теперь поехали! В самом начале нам нужно выкачать страничку. Записываем ее адрес и открываем по нему соединение. Далее идет проверка — если соединение успешно, можно считать весь файл (не мудрствуя лукаво указываем 200000 байт для считывания, что явно больше размера открываемого файла), если произошла ошибка открытия, предупреждаем об этом посетителя и выводим ему что угодно, например баннер.
Этап 1.
$rf = trim (chop ($rf)); — этой мудреной комбинацией мы значительно уменьшим объем обрабатываемых данных, так как уберем повторяющиеся пробелы и пробелы в конце и в начале файла. Потом нам нужно определиться с местом, откуда мы будем выводить информацию. Анализ кода дает нам очень эффективный механизм, и мы им непременно воспользуемся.
$s = strpos($rf, » — эта команда позволяет найти номер позиции указанной последовательности символов в строке, куда мы считали весь код файла. Результат помещается в переменную $s
$rf = substr($rf, $s); — жестоко обрезаем все, что находится перед этой комбинацией. В том числе и баннеры, кстати.
Этап2.
Делаем почти тоже самое, но только для конца файла. Файл оказывается обрезан с начала и с конца так, как нам того хочется. Обращаю Ваше внимание, что в данном случае все оказалось очень просто, но иногда приходится применять другие метода для вырезки кода, так как нет столь четких границ. Но почти всегда можно что-то придумать. В результате этой обработки у нас уже есть почти все, что надо. В принципе можно было просто вывести все на экран, но есть один нюанс, который нужно учитывать. Это — ссылки. Они не абсолютные, а относительные. Хорошо хоть, их мало… А в таком случае проблема решается просто.
Этап3.
Берем, и заменяем то, что есть на то, что нам нужно. Например:
$rf = str_replace («/catalog/»,»http://win.subscribe.ru/catalog/», $rf);
Эта строчка кода позволяет нам заменить во всей строке $rf относительные ссылки на абсолютные. Точно так же поступаем со всеми остальными ссылками, которые встречаются в коде странички. Грубо, но точно…
Этап4.
Тут мы просто выводим результат на экран посетителю. А этот результат — нужный нам код HTML странички, который и будет отображен браузером. Если Вы хотите интегрировать этот код к себе, Вам скорее всего придется сделать еще одно — расправиться с таблицами, которые норовят по ширине вылезть из Вашего дизайна. Но тут уж подумайте сами. Ничего сложного нет — находит, что отвечает за размер страницы, и заменяем это на пустую строку.
Результат — на экране. Если хотите посмотреть как это все работает в натуре, посетите страницу http://virtual.bresttelecom.by/komputer/ Там есть этот пример, а так же два других, но предлагаю посмотреть на них самим. На сегодня все.
Приходит очень много вопросов по теме установки и настройки РНР и Apache. Честно говоря, я сам в этом деле не очень хорошо разбираюсь (в установке под Win), но зато могу посоветовать к кому обратиться. http://www.design-studios.ru/php/apache/ Этот сайт и его автор, надеюсь, смогут Вам помочь в нелегком деле настройки. Там выложены самые лучшие и подробные описания, много полезной информации по теме. Пользуйтесь…
Telegram Grabber
Бот копирует новые посты из указанных каналов в канал модерации, в канале модерации вы выбираете, какой пост отправить в ваш основной канал.
Инструкция перед запуском
Шаг 1: Создание базы данных
- Создать базу данных с названием «bd.db» в корневом каталоге проекта.
- В базе данных автоматически создается таблица «DataBase» со столбцами «username» и «message_id».
- В базе данных автоматически создается таблица «config» со столбцами «donor», «moder», «channel».
- В таблицу «DataBase» записывается информация о скопированных постах. (Не редактировать);
- В таблицу «config» добавляются и удаляются каналы откуда копировать посты (донор), на какой канал копировать (модератор) и на какой канал публиковать посты.
Шаг 2: Создание ботов
- Зарегистрировать приложение на https://my.telegram.org/apps , получить api id и api hash.
- Создать канал, в который будут копироваться все новые посты. (важно канал сделать открытым)
- Создать основной канал, в который будут публиковаться посты, выбранные из первого канала.
- Создать бота, сохранить токен. (Бот добавляет/удаляет в базе донора, модератора и основной канал).
Шаг 3: Переменные виртуального окружения
1. API_ID="Вставить из шага 2.1"
2. API_HASH="Вставить из шага 2.1"
3. TOKEN="Вставить из шага 2.4"
4. USER_ID="Получить используя бот @userinfobot"
Требования
Pyrogram==1.0.7
aiogram==2.12.1
Запуск
Запуск на Linux
cd python_bot/
В первый раз нужно запустить бота и подтвердить вход номером телефона, поэтому:
python3 bot_grabber.py
Ввести номер телефона и код подтверждения
ctrl + c
nohup python3 -u ./bot_grabber.py &
cd ..
cd restart_bot/
nohup python3 -u ./bot_restart.py &
Как пользоваться
Добавьте вашего бота в канал модерации и основной канал, сделайте его админом.
Когда в каналах появляется пост, он копируется в канал модер с присвоением ID.
Для того, что бы отправить пост в основной канал нужно отправить в ответ ID поста.
PS на канал нужно быть подписанным.
Управление БД через Telegram
Используя бот из шага 2.4 есть возможность вносить изменения в базу по каналам донорам, модерации и основного канала,
с помощью всплывающей клавиатуры.
Для добавления каналов вставляете ссылку на канал, к примеру просто durov
Нажать Донор -> ввести название -> выбрать Добавить или Удалить
Нажать Модер -> ввести название -> выбрать Добавить или Удалить
Нажать Канал -> ввести название -> выбрать Добавить или Удалить