Python — webscraping для перехода на несколько уровней глубины внутри страницы с модулем запросов

#python #web-scraping #python-requests

#python #веб-очистка #python-запросы

Вопрос:

У меня есть скрипт Python3, который выполняет веб-очистку на основе URL-адресов, предоставленных в файле csv. Я пытаюсь добиться следующего:

1.) Получите страницу по URL-адресу, указанному в файле CSV

2.) Очистите его и выполните поиск адресов электронной почты с помощью regex beautifulsoup, затем, если электронная почта найдена, сохраните ее в файле results.csv

3.) Поиск всех других (ссылок) на странице

4.) Перейдите к / получите все ссылки, найденные на 1-й странице (1-й уровень очистки), и сделайте то же самое

5.) Выполните то же самое в зависимости от определенного пользователем уровня глубины (если пользователь скажет перейти на 3 уровня глубже, чем это было бы сделано: получить страницу с 1-го уровня (url из CSV-файла) и сделать то, что необходимо на этой странице -> Получить все страницы со 2-го уровня(очищенные ссылки с 1-го уровня) и делайте то, что нужно -> Получите все страницы с 3-го уровня (очищенные ссылки со 2-го уровня) и делайте то, что нужно -> и так далее…

Как мне создать цикл, который будет обрабатывать очистку на уровне глубины? Я пробовал играть с несколькими вариантами циклов for и while, но я не могу найти рабочее решение.

Это код, который у меня есть в настоящее время (в настоящее время он может обрабатывать только очистку 1-го уровня):

 from bs4 import BeautifulSoup
import requests
import csv
import re

import time
import sys, os

#Type the amount of max level of depth for this instance of script
while True:
    try:
        max_level_of_depth = int(input('Max level of depth for webscraping (must be a number - integer): '))
        print('Do not open the input and neither the output CSV files before the script finishes!')
        break
    except:
        print('You must type a number (integer)! Try again...n')
        
#Read the csv file with urls
with open('urls.csv', mode='r') as urls:
    #Loop through each url from the csv file
    for url in urls:
        #Strip the url from empty new lines
        url_from_csv_to_scrape = url.rstrip('n')
        print('[FROM CSV] Going to '   url_from_csv_to_scrape)
        #time.sleep(3)
        i = 1
        #Get the content of the webpage
        page = requests.get(url_from_csv_to_scrape)
        page_content = page.text
        soup = BeautifulSoup(page_content, 'lxml')
        #Find all <p> tags on the page
        paragraphs_on_page = soup.find_all('p')
        for paragraph in paragraphs_on_page:
            #Search for email address in the 1st level of the page
            emails = re.findall(r'[a-zA-Z0-9_-.] @[a-zA-Z0-9_-.] .[a-zA-Z]{2,5}', str(paragraph))
            #If some emails are found on the webpage, save them to csv
            if emails:
                with open('results.csv', mode='a') as results:
                    for email in emails:
                        print(email)
                        if email.endswith(('.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG')):
                            continue
                        results.write(url_from_csv_to_scrape   ', '   email   'n')
                        print('Found an email. Saved it to the output file.n')
                    results.close()
        #Find all <a> tags on the page
        links_on_page = soup.find_all('a')
        #Initiate a list with all links which will later be populated with all found urls to be crawled
        found_links_with_href = []
        #Loop through all the <a> tags on the page
        for link in links_on_page:
            try:
                #If <a> tag has href attribute
                if link['href']:
                    link_with_href = link['href']
                    #If the link from the webpage does not have domain and protocol in it, prepend them to it
                    if re.match(r'https://', link_with_href) is None and re.match(r'http://', link_with_href) is None:
                        #If the link already has a slash in it, remove it because it will be added after prepending
                        link_with_href = re.sub(r'/', '', link_with_href)
                        #Prepend the domain and protocol in front of the link
                        link_with_href = url_from_csv_to_scrape   link_with_href
                        #print(link_with_href)
                    found_links_with_href.append(link_with_href)
                    found_links_with_href_backup = found_links_with_href
            except:
                #If <a> tag does not have href attribute, continue
                print('No href attribute found, going to next <a> tag...')
                continue
  

Любая помощь приветствуется.

Спасибо

Комментарии:

1. для использования этой задачи scrapy см.: scrapy.org

2. Я буду развертывать этот скрипт на виртуальной машине, на которой использование библиотеки scrapy запрещено. Я должен использовать requests и beautifulsoup для этого скрипта.. Не могу использовать что-либо еще, кроме библиотек, которые я уже импортировал в коде, который я опубликовал.

3. @rogatoo в этом случае создайте цикл, который найдет все ссылки на странице и выполнит функцию для новых созданных ссылок

4. @ZarakiKenpachi не уверен, что именно вы имеете в виду. у меня уже есть цикл for для перебора URL-адресов из моего CSV-файла. Не уверен, как создать внутренний цикл, чтобы просто повторять конечное время (на основе ввода пользователя), чтобы углубиться в страницу..

5. используйте while any url link found on page -> do something -> check if new links are found

Ответ №1:

Вот некоторый псевдокод:

 def find_page(page):
    new = re.findall('regex', page.text)
    new_pages.append(new)
    return len(new)

check = True
new_pages = [page]
used_pages = []
while check:

    for item in new_pages:
        if item not in used_pages:
            found = find_page(item)
            if found == 0:
                check = False
            else:
                'find emails'
            
        used_pages.append(item)
  

Комментарии:

1. Спасибо за ваше предложение! Однако это не позволяет обрабатывать цикл, итерации которого будут определены пользователем (если он скажет 2, тогда он также должен перебирать ссылки, найденные на 1-й странице, и также очищать их)

2. @rogaloo это должно очистить электронные письма со всех созданных страниц. вам не нужно указывать какие-либо входные данные от пользователя

3. Да, но, как я упоминал в своем первоначальном сообщении, мне нужно иметь возможность определять уровень глубины очистки. В частности (скопировано из моего исходного сообщения): получить страницу с 1-го уровня (url из CSV-файла) и сделать то, что нужно на этой странице -> Получить все страницы со 2-го уровня (очищенные ссылки с 1-го уровня) и делать то, что нужно -> Получить все страницы с 3-го уровня (url-адрес из CSV-файла).очищенные ссылки со 2-го уровня) и делайте то, что необходимо -> и так далее (останавливаясь на уровне глубины / количестве, определенном пользователем)

4. @rogaloo затем вам нужно указать, как программа будет определять уровень для вас. Если под уровнем вы подразумеваете подстраницу, то вам нужно проверить текущий URL на уровень позиции.