В этой статье будет рассказано о том, как
используя модули Perl LWP::UserAgent и MIME::Lite скачать
HTML страницу и отослать ее в письме вместе со
всеми вложенными изображениями.
Применяя изложенный метод я ежедневно
получаю свежие анекдоты в свой почтовый
ящик - ну лень мне каждый день лазить в Инет
🙂
Для работы нам потребуются следующие
модули (взять их можно на CPAN http://www.cpan.org)
- LWP::UserAgent - класс пользовательских
агентов WWW - MIME::Lite - облегченный MIME кодер/декодер
- URI::URL - работа с URL
- HTML::LinkExtor - получение списка всех URL в
документе - Time::Local - преобразует компоненты полного
времени в секунды
Для примера разберем, как выкачиваются
все истории за день с сайта "Анекдоты из
России" (http://www.anekdot.ru).
Сайт постоянно обновляется, поэтому имеет
смысл выкачивать все истории за вчера, там
содержимое уже меняться не будет. Адрес
нужной нам страницы строится следующим
образом :
сайт анекдотов/an/an год месяц/o год месяц день.html
причем от года берутся только 2 последние
цифры, а месяц и день дополняется до 2
символов нулями слева, если это необходимо.
Таким образом, страница http://www.anekdot.ru/an/an0206/o020629.html
содержит все истории за 29 июня 2002 года.
Небольшое лирическое отступление для тех,
кто только начал осваивать Perl.
Как скачать WEB страницу ?
require LWP::UserAgent; $ua = LWP::UserAgent->new;
$ua-> proxy(['http', 'ftp'],
'адрес прокси-сервера');
$req = new HTTP::Request('GET' =>
'страница для скачивания');
if ($res->is_success)
{
$page = $res->content;
}
Как отправить письмо с прикрепленными
файлами?
require MIME::Lite;
$msg = MIME::Lite->new( From =>'Ваш@Адрес.com',
To =>'Адрес@Получателя.com', Subject =>'Тема
сообщения', Type => 'multipart/related');
$msg->attach( Type
=>'text/plain; charset=windows-1251', Data => текст письма);
$msg->attach( Type => 'image/gif', Path => путь к файлу,
Filename =>'img.gif');
$msg->send();
Рассмотрим по шагам работу программы.
- Определяем URL документа
- Скачиваем содержимое WEB страницы
- Ищем и скачиваем все содержащиеся на
странице изображения - Меняем ссылки относительно документа на
их абсолютное значение - Присоединяем внешние файлы CSS,JavaScript
- Кодируем все изображения и собираем MIME
объект - Отсылаем получившееся письмо по
электронной почте
Техническую реализацию скрипта я буду
описывать схематически, если что будет не
понятно - смотрите исходник.
C ANEKDOT.RU все истории за вчера. Вычисляем
дату - полночь вчерашнего дня. Дополняем
дату нулями слева.
$sutki=24*60*60;
($tek_day,$tek_month,$tek_year)=(localtime)[3,4,5];
$in1=timelocal(0,0,0,$tek_day,$tek_month,$tek_year);
$in2=$in1-$sutki;
($tek_day,$tek_month,$tek_year)=(localtime($in2))[3,4,5];
$tek_month++; $tek_year+=1900;
if ($tek_month<10)
{
$tek_month="0".$tek_month
}
if ($tek_day<10)
{
$tek_day="0".$tek_day;
}
$an_year=substr($tek_year, 2, 2);
Страница для скачивания. Определяем адрес
страницы согласно приведенного шаблона.
$url_page= "http://www.anekdot.ru/an/an".$an_year.$tek_month."
/o".$an_year.$tek_month. $tek_day.".html";
Скачиваем содержимое страницы используя
модуль LWP.
if ($url_page && $url_page=~/^(https?|ftp|file|nntp):\/\//)
{
my $req = new HTTP::Request('GET' => $url_page);
my $res = $ua->request($req);
$gabarit = $res->content;
}
Подключаем внешний CSS и JavaScript. Тут все
очень упрощенно показано, но разобраться
можно - качаем файл со скриптами и
подставляем его в нужное место HTML документа.
внешний CSS = '<style type="text/css">'."\n".'<!--'."\n".
файл со стилями ."\n-->\n</style>\n";
документ HTML =~s/<link([^<>]*?)href="?([^\" ]*)"?([^>]*)>/
внешний CSS /iegmx; внешний JavaScript = '<script><!--'."\n".
файл со скриптами ."\n-->\n</script>\n";
документ HTML =~s/<script([^>]*)src="?([^\" ]*js)"?([^>]*)>/
внешний JavaScript /iegmx;
Проходимся по всем ссылкам и меняем
относительный путь на абсолютный.
Необходимо это для того, чтобы нажав на
ссылку в письме мы попадали именно туда,
куда указывала ссылка с документа,
размещенного в Инете.
my $analyseur = HTML::LinkExtor->new;
$analyseur->parse($gabarit);
my @l = $analyseur->links; foreach my $url (@l)
{
my $urlAbs = URI::WithBase->new($$url[2],$racinePage)->abs;
chomp $urlAbs;
if ( ($$url[0] eq 'a') && ($$url[1] eq 'href') && ($$url[2])
&& (($$url[2]!~m!^http://!) && ($$url[2]!~m!^mailto:!)) )
{
$gabarit=~s/\s href= [\"']? $$url[2] [\"']?/ href="$urlAbs"/gimx;
}
}
Выбираем из документа все изображения,
скачиваем картинку, определяем тип и
возвращаем ее, закодированную в MIME.
if ( ((lc($$url[0]) eq 'img') || (lc($$url[0]) eq
'src')) )
{
push(@mail, create_image_part($urlAbs));
}
if (lc($ur)=~/gif$/)
{
$type="image/gif";
}
elsif (lc($ur)=~/jpg$/)
{
$type = "image/jpg";
}
else
{
$type = "application/x-shockwave-flash";
}
my $res2 = $ua->request(new HTTP::Request('GET' => $ur));
$buff1=$res2->content;
$file_name = substr($ur,rindex($ur,"/")+1,length($ur));
# кодируем очередную картинку my
$mail = new MIME::Lite( Data => $buff1, Encoding =>'base64', 'Filename'=>$file_name);
$mail->attr('Content-type'=>$type); $mail->attr('Content-Location'=>$ur);
Создаем MIME объект, указываем от кого и
кому письмо, тему сообщения. Если на
странице изображений нет - тип сообщения text/html,
если есть картинки - multipart/related.
$mail = new MIME::Lite 'From' => 'somebody@somewhere.com',
'To' => $to_email, 'Subject' => $url_page, 'Data' => $html; $mail->attr("Content-type"
=> $content_type);
if (@mail)
{
$mail->replace("Type" => "multipart/related");
# присоеденяем каждую картинку
foreach (@mail) {$mail->attach($_);
}
}
Отсылаем страницу по почте. Можно
использовать SMTP или sendmail.
MIME::Lite->send('smtp', " адрес SMTP
сервера ", Timeout=>60); $mail->send();
Выполнение программы.
Помещаем наш скрипт в каталог, откуда
разрешено выполнение программ и делаем
файл исполняемым
chmod 750 /usr/local/www/cgi-bin/html_on_email3.pl
Для того, чтобы окончательно все
автоматизировать, вешаем наш скрипт на CRON.
Для этого в файл /etc/crontab добавляем строчку
0 9 * * * root /usr/local/www/cgi-bin/html_on_email3.pl
и каждое утро в 9 часов читаем свежие
анекдоты.
Для того, чтобы скрипт работал и в
локальной сети необходимо установить
соединение с Инетом и явно указать адреса
прокси- и SMTP - сервера.
$ua->proxy(['http', 'ftp'], 'http://10.0.0.3:3128/'); MIME::Lite->send('smtp',
"10.0.0.1", Timeout=>60);
В завершение хочу заметить, что все можно
было написать и по-другому, более красиво.
Но программа работает, а большего от нее и
не требуется 🙂
Исходник программы http://takiedela.narod.ru/press/html_on_email3.pl