Парсинг сайтов на Python. Часть 1

Что такое Парсинг и что это означает ?

Парсинг это синтаксический анализ или разбор  (англ. parsing) данных. По факту это означает разбор содержимого страницы на отдельные составляющие, в нашем случае html кода страниц(ы).

В этой статье мы будем автоматически вытаскивать нужную нам информации со страницы веб-сайта и сохранять в формате CSV.

CSV (от англ. CommaSeparated Values — значения, разделённые запятыми) — текстовый формат, предназначенный для представления табличных данных. 

Задача номер ноль.

Что бы получить данные с сайта первым делом надо получить код (html) страницы этого сайта. Для решения этой задачи будем использовать библиотеку requests . requests это по сути обертка библиотеке urllib которая упрощает работу с запросами к веб-серверу и т.д. Что очень удобно, получить страницу занимает всего две строчки :

import requests
# pip install requests 

def get_html(url):
    r = requests.get(url)    # Получаем метод Response
    r.encoding = 'utf8'      # У меня были проблемы с кодировкой, я задал в ручную
    return r.text            # Вернем данные объекта text

Мы отправляем GET запрос серверу requests.get(url) . И возвращаем данные которые содержаться в поле text .

Задача номер один.

Собственно теперь у нас есть данные что бы их парсить. В качестве самого парсера мы будем использовать библиотеку BeautifulSoup . Soup переводиться как суп , не поверите. Вот такое забавное название, будем варить суп ) Есть и другие библиотеки в том числе и входящие уже в Питон.

Теперь нам надо придумать откуда мы будем вытаскивать информацию и какую. Для примера возьмем сайт 3dnews.ru и будем собирать все заголовки статей с раздела Новости Hardwear .

Так как структура, верстка и т.д. всех сайтов разная нам надо еще понять где именно хранятся заголовки статей. Есть конечно мощные, универсальные парсеры но это не про нас. Я новичок и сатья рассчитана на таких же новичков. По этому идем в инструмент разработчика и ищем наши заголовки. Тут конечно требуется базовое знание языка html . Но я думаю даже если вы совсем не знакомы быстро разберетесь.

Давайте перейдем к коду парсера и я вам постараюсь все разъяснить:

from bs4 import BeautifulSoup
# pip install beautifulsoup4
# pip install lxml

def get_head(html):
    soup = BeautifulSoup(html, 'lxml') #  Создаем сам объект , передаем в него наш код страницы (html)  

Создаем сам объект , передаем в него наш код страницы (html) и 'lxml' , в качестве интерпретатора кода. LXML библиотека для обработки XML и HTML .

Теперь с помощью метода fine() найдем блок со статьями, <div id="section-content"> . Уже в этом блоке найдем все теги заголовка <h1> методом fine_all() в которых собственно и содержится название статьи. Нам вернеться список всех заголовков в этом блоке.

Тег  <div> — это блочный элемент, внутри которого могут находиться другие теги, содержание веб страницы. Своего рода, это контейнер, который можно легко видоизменять и выводить в любом месте веб страницы с помощью CSS. 

 head = soup.find('div', id='section-content').find_all('h1')

Кроме id есть еще class, но слово класс зарезервировано в питон по этому в библиотеке используется class_ = 'что то там'

Наш список все еще является объектом BeautifulSoup и мы можем к нему применять все методы библиотеки. Переберем весь список тегов и вытащим из него текс методов .string .

heads = []
for i in head:
   heads.append(i.string)

Возвращаем уже текстовый список с заголовками статей.

 def get_head(html):
    soup = BeautifulSoup(html, 'lxml')
    head = soup.find('div', id='section-content').find_all('h1')
    heads = []
    for i in head:
       heads.append(i.string)
    return heads 

Но одни заголовки это мало , давайте еще вытащим ссылки на эти статьи. Смотрим внимательно на код страницы. По факу заголовки и есть ссылки , тег <h1> обернут в тег <a class="entry-header" >. Мы немного меняем наш код, в блоке мы ищем теперь все теги <a> с class="entry-header" .

head = soup.find('div', id='section-content').find_all('a', class_="entry-header")

Теперь мы в цикле вытаскиваем ссылки и заголовки, не забываете что мы может применять все методы библиотеки.

for i in head:
    link = 'https://3dnews.ru' + i.get('href') # Методом get() получим ссылку из href 
    heads= i.find('h1').string # Вытащим текс из тега.

Создадим словарь и отправим его на запись в файл:

data = {'head': heads,
        'link': link}
csv_read(data) # Вызов функции записи

Задача номер три.

Теперь создадим функцию записи в файл в формате CSV.

import csv
# Стандартная библиотека, установка не нужна.
def csv_read(data):
    with open("data.csv", 'a') as file:

Открываем\создаем файл , ‘a’ — значит добавить данные в конец файла, если файла нет создать.

   writer = csv.writer(file)
   writer.writerow((data['head'], data['link']))

Для записи нам надо получить объект writer, который возвращается функцией csv.writer(file). В эту функцию передается открытый файл. А собственно запись производится с помощью метода writer.writerows(data) Этот метод принимает набор строк.

Ну и весь код целиком:

import requests
from bs4 import BeautifulSoup
import csv
# pip install beautifulsoup4
# pip install lxml

def get_html(url):
    r = requests.get(url)    # Получим метод Response
    r.encoding = 'utf8'
    return r.text   # Вернем данные объекта text


def csv_read(data):
    with open("data.csv", 'a') as file:
        writer = csv.writer(file)
        writer.writerow((data['head'], data['link']))

def get_link(html):
    soup = BeautifulSoup(html, 'lxml')
    head = soup.find('div', id='section-content').find_all('a', class_="entry-header")
    for i in head:
        link = 'https://3dnews.ru' + i.get('href')
        heads= i.find('h1').string
        data = {'head': heads,
                 'link': link}
        csv_read(data)


data = get_link(get_html('https://3dnews.ru/news'))
#https://3dnews.ru/news