Рассмотрены возможности поиска на странице по типу тега (ссылки) и классу тега. Для парсинга используется библиотека BeautifulSoup.
Часть 1. Парсер
Несмотря на то, что с момента релиза Python 3.5 прошло уже достаточно много времени, большинство хороших библиотек до сих под его не поддерживают.
Единственной библиотекой-парсером, "из коробки" поддерживающей 3-ю версию оказался BeautifulSoup.
Для его установки установки можно использовать команду:
pip install beautifulsoup4
Более подробно почитать об установке и первых шагах можно в официальной документации.
Часть 2. Задача
В моем случае стояла задача получить список сайтов с одного сайта (esir.gov.spb.ru) , где адрес сайта отмечен HTML-классом "small" и на сайтах из этого списка попытаться найти e-mail. Было выдвинуто предположение, что e-mail'ы на сайтах должны быть кликабельны, т.е. обернуты в ссылки. (В принципе это не так, но количества полученных адресов для моих целей было достаточно).
Часть 3. Реализация
Парсер адресов сайтов
Для получения тегов с нужным классом используется функция soup.findAll(attrs={"class":"small"})
Для парсинга используем следующий код:
Для парсинга используем следующий код:
from bs4 import BeautifulSoup
from urllib.request import urlopen
i = 1
while i<=26: #На сайте 26 страниц с полезной информацией
# Загружаем страницу
page = urlopen("https://esir.gov.spb.ru/category/21/?page="+str(i))
#Парсим страницу с помощью BeautifulSoup
soup = BeautifulSoup(page, 'html.parser')
#Получаем со страницы все теги с классом small
urls_tag = soup.findAll(attrs={"class":"small"})
#Добавляем адреса сайтов в список и запусткаем обработку полученного полученного сайта в отдельном потоке
for element in urls_tag:
urls.append(element.string)
i=i+1
В процессе выполнения кода получаем список адресов сайтов
Реализация паука для поиска e-mail
Для реализации паука будем использовать рекурсивный обход, попутно записывая в список посещенные страницы
Для поиска используется функция soup.findAll('a'), возвращающая все теги "а"
Для поиска используется функция soup.findAll('a'), возвращающая все теги "а"
from bs4 import BeautifulSoup
from urllib.request import urlopen
import threading
eMails = []
urls = []
last_urls =[]
def findEmail(url, TTL, mainUrl):
eMail = ''
try:
#Сразу отсеим ссылки на документы pdf
if url.find("pdf") < 0:
# Загрузаем страницу сайта
page = urlopen(url)
except Exception:
return eMail
#Парсим полученную страницу
soup = BeautifulSoup(page, 'html.parser')
#Получаем все теги-ссылки
page_urls = soup.findAll('a')
#Обрабатываем полученные ссылки
for element in page_urls:
#Если тег не пустой
if element.string != None:
#Если в тексте тега содержится символ Собака
if element.string.find('@')>=0:
# Мы нашли e-mail, возвращаем его
eMail = element.string
return eMail
else:
# Если время жизни паука еще не кончилось
if TTL > 0:
try:
#Проверяем, что ссылка на страницу и еще не была посещена и находится в пределах обыскиваемого сайта
if element['href'].find(mainUrl) >= 0 and last_urls.count(element['href'])<1:
#Добавляем ссылку в посещенные
last_urls.append(element['href'])
#Пробуем получить e-mail с этой страницы, уменьшив время жизни
eMail_1 = findEmail(element['href'], TTL-1,mainUrl)
#Если получили в результате адрес почты
if eMail_1.find('@')>=0:
return eMail_1
except Exception:
eMail_1 = ''
return eMail
#Фукция-обертка для удобного запуска потока
def startFinder(url, TTL, mainUrl):
#Отчитываемся о том, что запустили поток
print("thread " + mainUrl + " start \n")
#Ищем адреса на сайте (mainUrl нужен для того, чтобы оставаться в пределах сайта)
eM = findEmail(url, TTL,mainUrl)
#Добавляем в список
eMails.append(eM)
Записываем полученные e-mail в файл
#Открываем файл на запись (Если файла нет, он создастся автоматически)
f = open( 'emails.txt', 'w' )
#Записываем по очереди на отдельные строки все элементы полученного списка
for item in eMails:
#Если длинна больше трех (убираем пустые строки с сайтов, где не было найдено e-mail)
if len(item) > 3:
print(item)
f.write("%s\n" % item)
#Закрываем файл
f.close()
Итог
В итоге получен следующий скрипт:
Напомню, что он является ознакомительным и не претендует на оптимальность и непогрешимость.
Напомню, что он является ознакомительным и не претендует на оптимальность и непогрешимость.
Комментариев нет :
Отправить комментарий