Ограничить глубину страницы на сканере - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть скребок, который берет список URL-адресов и сканирует их на наличие дополнительных ссылок, после чего следует поиск всего, что выглядит как электронное письмо (с использованием REGEX), и возвращает список URL-адресов / адресов электронной почты.

В настоящее время он настроен на ноутбуке Jupyter, поэтому я могу легко просматривать результаты во время тестирования. Проблема в том, что для запуска требуется вечность - потому что я не ограничиваю глубину скребка (для каждого URL).

В идеале, скребок должен был бы go иметь максимальную глубину 2-5 страниц от каждой Начальный URL.

Вот что у меня есть:

Сначала я импортирую свои зависимости:

import os, re, csv, scrapy, logging
import pandas as pd
from scrapy.crawler import CrawlerProcess
from scrapy.linkextractors.lxmlhtml import LxmlLinkExtractor
from googlesearch import search
from time import sleep
from Urls import URL_List

И я отключаю журналы и предупреждения для использования Scrapy внутри Блокнот Jupyter:

logging.getLogger('scrapy').propagate = False

Оттуда я извлекаю URL-адреса из моего файла URL:

def get_urls():
    urls = URL_List['urls']

Затем я настраиваю своего паука:

class MailSpider(scrapy.Spider):
    name = 'email'
    def parse(self, response):

Я ищу ссылки внутри URL.

        links = LxmlLinkExtractor(allow=()).extract_links(response)

Затем принимаю в качестве входных данных список URL, считывая их исходные коды один за другим.

        links = [str(link.url) for link in links]
        links.append(str(response.url))

Я отправляю ссылки одним методом синтаксического анализа другому. И установите аргумент обратного вызова, который определяет, какому методу должен быть отправлен URL-адрес запроса.

        for link in links:
            yield scrapy.Request(url=link, callback=self.parse_link)        

Затем я передаю URL-адреса методу parse_link - этот метод применяет регулярное выражение findall для поиска писем

    def parse_link(self, response):
        html_text = str(response.text)
        mail_list = re.findall('\w+@\w+\.{1}\w+', html_text)
        dic = {'email': mail_list, 'link': str(response.url)}
        df = pd.DataFrame(dic)
        df.to_csv(self.path, mode='a', header=False)

Список google_urls передается в качестве аргумента, когда мы вызываем метод процесса для запуска Spider, путь определяет, где сохранить файл CSV.

Затем я сохраняю эти электронные письма в файле CSV:

def ask_user(question):
    response = input(question + ' y/n' + '\n')
    if response == 'y':
        return True
    else:
        return False

def create_file(path):
    response = False
    if os.path.exists(path):
        response = ask_user('File already exists, replace?')
        if response == False: return 
    with open(path, 'wb') as file: 
        file.close()

Для каждого веб-сайта я создаю фрейм данных со столбцами: [электронная почта, ссылка] и добавляю его к ранее созданному файлу CSV.

Затем я собираю все это вместе:

def get_info(root_file, path):  
    create_file(path)
    df = pd.DataFrame(columns=['email', 'link'], index=[0])
    df.to_csv(path, mode='w', header=True)

    print('Collecting urls...')
    google_urls = get_urls()

    print('Searching for emails...')
    process = CrawlerProcess({'USER_AGENT': 'Mozilla/5.0'})
    process.crawl(MailSpider, start_urls=google_urls, path=path)

    process.start()

    print('Cleaning emails...')
    df = pd.read_csv(path, index_col=0)
    df.columns = ['email', 'link']
    df = df.drop_duplicates(subset='email')
    df = df.reset_index(drop=True)
    df.to_csv(path, mode='w', header=True)

    return df

get_urls()

Наконец, я определяю ключевое слово и запускаю скребок:

keyword = input("Who is the client? ")
df = get_info(f'{keyword}_urls.py', f'{keyword}_emails.csv')

В списке из 100 URL-адресов я получил 44 000 результатов с синтаксисом адресов электронной почты.

Кто-нибудь знает, как ограничить глубину?

1 Ответ

1 голос
/ 11 февраля 2020

Установите DEPTH_LIMIT в вашем Пауке, как это

class MailSpider(scrapy.Spider):
    name = 'email'

    custom_settings = {
        "DEPTH_LIMIT": 5
    }

    def parse(self, response):
        pass
...