Рубрики
Без рубрики

Полное руководство по соскабливания в Интернете для самых популярных фильмов на телевидении

Автор оригинала: Bert Carremans.

В этой статье я покажу, как просматривать Интернет для фильмов на высшем уровне с Струпкие рамки Отказ цель Из этого веб-скребка – найти фильмы, которые имеют высокий рейтинг пользователя на База данных фильма Отказ Список с этими фильмами будет храниться в SQLite Database и по электронной почте Отказ Таким образом, вы знаете, вы никогда не пропустите блокбастер на телевизор снова.

Я начинаю с онлайн-телевидения, чтобы найти фильмы на бельгийских телеканалах. Но вы можете легко адаптировать мой код, чтобы использовать его для любого другого веб-сайта. Чтобы сделать вашу жизнь проще при сострании пленок, убедитесь, что веб-сайт, который вы хотите соскребать:

  • имеет HTML теги с приемлемый класс или идентификатор
  • Использует классы и идентификаторы в последовательный способ
  • есть хорошо структурированные URL
  • Содержит все актуальные Телевизионные каналы на одной странице
  • имеет Отдельная страница в будний день
  • Списки только фильмы И никакие другие типы программ, таких как живые шоу, новости, репортажа и так далее. Если вы не можете легко отличить фильмы с других типов программ.

С результатами найдены мы будем царапать База данных фильма (TMDB) для рейтинга фильма и другой информации.

Я буду соскребать следующую информацию о фильмах:

  • Название фильма
  • ТВ канал
  • время, когда фильм начинается
  • Дата фильма на телевидении
  • жанр
  • участок
  • Дата выпуска
  • Ссылка на страницу сведений на TMDB
  • Рейтинг TMDB.

Вы можете дополнить этот список со всеми актерами, директором, интересными фактами фильма, и так далее – вся информация, о которой вы хотели бы узнать больше о.

В Scrapy эта информация будет храниться в полях Предмет Отказ

Я собираюсь предположить, что у вас установлена сцепка. Если нет, вы можете следовать превосходному Руководство по установке Scraphy Отказ

Когда Scrapy установлен, откройте командную строку и перейдите в каталог, где вы хотите сохранить сцепное проект. Затем запустите:

scrapy startproject topfilms

Это создаст структуру папки для проекта верхних пленок, как показано ниже. Вы можете игнорировать файл topfilms.db сейчас. Это система SQLite, которую мы создадим в следующем сообщении в блоге на трубопроводах.

Мы будем работать с файлом items.py Отказ Items.py создается по умолчанию при создании вашего сцепного проекта.

Scrapy.item это контейнер, который будет заполнен во время соскабливания веб. Он будет держать все поля, которые мы хотим извлечь с веб-страницы. Содержимое элемента может быть доступно так же, как Python Dict Отказ

Открыть элементы .py и добавьте SCRAPY.ITEM КЛАСС Со следующими полями:

import scrapy
class TVGuideItem(scrapy.Item):
    title = scrapy.Field()
    channel = scrapy.Field()
    start_ts = scrapy.Field()
    film_date_long = scrapy.Field()
    film_date_short = scrapy.Field()
    genre = scrapy.Field()
    plot = scrapy.Field()
    rating = scrapy.Field()
    tmdb_link = scrapy.Field()
    release_date = scrapy.Field()
    nb_votes = scrapy.Field()

После запуска нового сцепного проекта у вас будет файл под названием трубопроводы.пи Отказ Откройте этот файл и скопируйте-вставьте код, показанный ниже. После этого я покажу вам шаг за шагом, что делает каждая часть кода.

import sqlite3 as lite
con = None  # db connection
class StoreInDBPipeline(object):
    def __init__(self):
        self.setupDBCon()
        self.dropTopFilmsTable()
        self.createTopFilmsTable()
def process_item(self, item, spider):
        self.storeInDb(item)
        return item
def storeInDb(self, item):
        self.cur.execute("INSERT INTO topfilms(\
        title, \
        channel, \
        start_ts, \
        film_date_long, \
        film_date_short, \
        rating, \
        genre, \
        plot, \
        tmdb_link, \
        release_date, \
        nb_votes \
        ) \
        VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )",
        (
        item['title'],
        item['channel'],
        item['start_ts'],
        item['film_date_long'],
        item['film_date_short'],
        float(item['rating']),
        item['genre'],
        item['plot'],
        item['tmdb_link'],
        item['release_date'],
        item['nb_votes']
        ))
        self.con.commit()
def setupDBCon(self):
        self.con = lite.connect('topfilms.db')
        self.cur = self.con.cursor()
def __del__(self):
        self.closeDB()
def createTopFilmsTable(self):
        self.cur.execute("CREATE TABLE IF NOT EXISTS topfilms(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \
        title TEXT, \
        channel TEXT, \
        start_ts TEXT, \
        film_date_long TEXT, \
        film_date_short TEXT, \
        rating TEXT, \
        genre TEXT, \
        plot TEXT, \
        tmdb_link TEXT, \
        release_date TEXT, \
        nb_votes \
        )")
def dropTopFilmsTable(self):
        self.cur.execute("DROP TABLE IF EXISTS topfilms")
        
    def closeDB(self):
        self.con.close()

Во-первых, мы начнем, импортируя SQLite Package и дать ему псевдоним Lite Отказ Мы также инициализируем переменную Con который используется для подключения к базе данных.

Создание класса для хранения элементов в базе данных

Далее вы создаете Класс с логическим именем. После включения трубопровода в файле настроек (больше на это позже) этот класс будет вызываться.

class StoreInDBPipeline(object):

Определение метода конструктора

Метод конструктора – это метод с именем __init__ Отказ Этот метод автоматически работает при создании экземпляра StoreindBPipipeline класс.

def __init__(self):
    self.setupDBCon()
    self.dropTopFilmsTable()
    self.createTopFilmsTable()

В методе конструктора мы запустим три других метода, которые определены ниже метода конструктора.

Метод setupdbcon

С методом setupdbcon мы создаем TopFilms база данных (если она еще не существовала) и сделать соединение с ним с соединить функция.

def setupDBCon(self):
    self.con = lite.connect('topfilms.db')
	self.cur = self.con.cursor()

Здесь мы используем Lite Lite для пакета SQLite. Во-вторых, мы создаем объект курсора с Курсор функция. С помощью этого объекта курсора мы можем выполнить операторы SQL в базе данных.

DroptopFilmStable Метод

Второй метод, который называется в конструкторе, это DroptopFilmStable Отказ Как говорит название, он бросит таблицу в базе данных SQLite.

Каждый раз, когда веб-скребок работает, база данных будет полностью удалена. Это зависит от вас, если вы хотите это сделать. Если вы хотите выполнить некоторые запросы или анализ данных фильмов, вы можете сохранить результаты соскабливания каждого прогона.

Я просто хочу увидеть лучшие рейтинговые фильмы ближайших дней и ничего более. Поэтому я решил удалить базу данных в каждом запуске.

def dropTopFilmsTable(self):
    self.cur.execute("DROP TABLE IF EXISTS topfilms")

С объектом курсора Cur Мы выполняем Падение утверждение.

Способ CreateTopFilmStable

После падения стола верхних фильмов нам нужно создать его. Это делается последним вызовом метода в методе конструктора.

def createTopFilmsTable(self):
    self.cur.execute("CREATE TABLE IF NOT EXISTS topfilms(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \
    title TEXT, \
    channel TEXT, \
    start_ts TEXT, \
    film_date_long TEXT, \
    film_date_short TEXT, \
    rating TEXT, \
    genre TEXT, \
    plot TEXT, \
    tmdb_link TEXT, \
    release_date TEXT, \
    nb_votes \
    )")

Снова мы используем объект курсора Cur Для выполнения Создать таблицу утверждение. Поля, которые добавляются к пленку таблицы Top, такие же, как в стиле склада, который мы создали ранее. Чтобы сохранить вещи легко, я использую точно такие же имена в таблице SQLite, как в элементе. Только ID поле дополнительное.

Примечание : хорошее приложение, чтобы посмотреть на ваши базы данных SQLite – это Плагин менеджера SQLite в Firefox Отказ Вы можете посмотреть это Учебник SQLite Manager на Youtube Чтобы узнать, как использовать этот плагин.

Method force_item метод

Этот метод должен быть реализован в классе трубопровода, и он должен вернуть дикт, элемент или исключение DropITem. В нашем веб-скребеке мы вернем товар.

def process_item(self, item, spider):
    self.storeInDb(item)
	return item

В отличие от других методов объяснения, он имеет два дополнительных аргумента. Предмет это было соскоблено и паук Это соскреболо предмет. Из этого метода мы запускаем Storeindb Метод и последующие возврата товара.

Метод StoreindB

Этот метод выполняет Вставить Заявление для вставки Scraped элемент в базу данных SQLite.

def storeInDb(self, item):
    self.cur.execute("INSERT INTO topfilms(\
    title, \
    channel, \
    start_ts, \
    film_date_long, \
    film_date_short, \
    rating, \
    genre, \
    plot, \
    tmdb_link, \
    release_date, \
    nb_votes \
    ) \
    VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )",
                     (
                         item['title'],
                         item['channel'],
                         item['start_ts'],
                         item['film_date_long'],
                         item['film_date_short'],
                         float(item['rating']),
                         item['genre'],
                         item['plot'],
                         item['tmdb_link'],
                         item['release_date'],
                         item['nb_votes']
                     ))
    self.con.commit()

Значения для полей таблицы поступают из элемента, который является аргументом для этого метода. Эти значения просто называются ценностью обамывания (помните, что элемент не более, чем дикт?).

Каждый конструктор имеет … деструктор

Ассортимент метода конструктора является методом деструктора с именем __del__ Отказ В методе деструктора для этого класса трубопроводов мы закрываем соединение с базой данных.

def __del__(self):
    self.closeDB()

Метод закрытия

def closeDB(self):
    self.con.close()

В этом последнем методе мы закрываем соединение с базой данных с Закрыть функция. Так что теперь мы написали полностью функциональный трубопровод. До сих пор остается последний шаг, чтобы включить трубопровод.

Включение трубопровода в настройках .py

Открыть settings.py Файл и добавьте следующий код:

ITEM_PIPELINES = {
    'topfilms.pipelines.StoreInDBPipeline':1
}

Целочисленное значение Указывает на заказ, в котором запускаются трубопроводы. Поскольку у нас есть только один трубопровод, мы назначаем его значение 1.

Теперь мы посмотрим на ядро Скалики, Паук Отказ Это то, где будет сделано тяжелая подъем вашего веб-скребка. Я покажу вам пошаговое, как создать один.

Импорт необходимых пакетов

Прежде всего, мы импортируем необходимые пакеты и модули. Мы используем Crawlspider Модуль, чтобы следовать ссылкам на протяжении всей онлайн-телевидения.

Правило и Linkextractor используются для определения того, какие ссылки мы хотим следовать.

config . Модуль содержит некоторые постоянные, такие как DOM_1, DOM_2 и Start_url которые используются в пауке. Модуль Config найден один каталог до текущего каталога. Вот почему вы видите два точки перед модулем конфигурации.

И, наконец, мы импортируем TVGUIDEITEM Отказ Этот TVGuideItem будет использоваться для содержения информации во время соскабливания.

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from fuzzywuzzy import fuzz
from ..config import *
from topfilms.items import TVGuideItem

Рассказывать паука, куда идти

Во-вторых, мы подкласс класс Crawlspider. Это сделано путем вставки CrawlSpider в качестве аргумента для Tvguidespider класс.

Мы даем паука A Имя Предоставьте разрешен_domains (например, themoviedb.org) и start_urls Отказ Start_urls находится в моем случае веб-страница телевизионного гида, поэтому вы должны изменить это на ваш собственный предпочтительный веб-сайт.

С правила и отрицать Аргумент Мы говорим паука, какие URL-адреса (нет) следовать на начальном URL. URL не следует следовать, указывается с регулярным выражением.

Я не заинтересован в фильмах, которые были показаны вчера, не позволяйте пауке следовать URL-адресам, заканчивающимся « Gisteren ».

Хорошо, но какие URL следует следовать паукам? Для этого я использую restrict_xpaths аргумент Он говорит, что следит за всеми URL с Класс = "Кнопка кнопки-бета" Отказ Это на самом деле URL с фильмами на предстоящую неделю.

Наконец, с Обратный вызов Аргумент Мы позволяем пауке знать, что делать, когда оно следует за одним из URL. Это будет выполнять функцию parse_by_day . Отказ Я объясню это в следующей части.

class TVGuideSpider(CrawlSpider):
    name = "tvguide"
    allowed_domains = [DOM_1, DOM_2]
    start_urls = [START_URL]
# Extract the links from the navigation per day
    # We will not crawl the films for yesterday
    rules = (
        Rule(LinkExtractor(allow=(), deny=(r'\/gisteren'), restrict_xpaths=('//a[@class="button button--beta"]',)), callback="parse_by_day", follow= True),
    )

Расставание последовых URL

parse_by_day . Функция, часть TVGuidesCreber, царапирует веб-страницы с обзором всех фильмов на канал в день. ответ Аргумент исходит из Запрос Это было запущено при запуске программы SCRAPING.

На веб-странице выскабливаются, вам необходимо найти элементы HTML, которые используются для отображения информации, которую мы заинтересованы. Два хороших инструмента для этого – Инструменты разработчика Chrome и Плагин Firebug в Firefox Отказ

Одна вещь, которую мы хотим хранить, это Дата Для фильмов мы соскоб. Эта дата можно найти в пункте (P) в Div с Class = "Grid__Col__inner" Отказ Очевидно, что это то, что вы должны изменить для страницы, вы соскабливаете.

С метод XPath объекта ответа мы извлекаем текст в абзаце. Я узнал много этого в Учебник о том, как использовать функцию XPath Отказ

Используя Extract_First Мы уверены, что мы не храним эту дату в виде списка. В противном случае это даст нам проблемы при хранении даты в базе данных SQLite.

После этого я выполняю некоторые очистки данных на Film_date_long и создать film_date_short с форматом yyyymmdd. Я создал этот формат YYYYMMDD, чтобы сортировать фильмы, хронологически позже.

Далее, телеканал соскоблен. Если это в списке Разрешенные_Channels (Определяется в модуле конфигурации), мы продолжаем царапать заголовок и время запуска. Эта информация хранится в элементе, которая инициируется TVGuideItem () Отказ

После этого мы хотим продолжить соскоб в базе данных фильма. Мы будем использовать URL https://www.themoviedb.org/search?query= Чтобы показать результаты поиска для фильма, соскобленного. Для этого URL мы хотим добавить заголовок фильма ( URL_PART в код). Мы просто повторно используем часть URL-адреса, которая находится в ссылке на веб-странице TV Guide.

С этим URL мы создаем новый запрос и продолжаем на TMDB. С request.meta [«Пункт»] Мы добавляем уже соскребные данные по запросу. Таким образом, мы можем продолжать заполнять наш текущий твисидем.

Уровень доходности на самом деле запускает запрос.

def parse_by_day(self, response):
    film_date_long = response.xpath('//div[@class="grid__col__inner"]/p/text()').extract_first()
    film_date_long = film_date_long.rsplit(',',1)[-1].strip()  # Remove day name and white spaces
    # Create a film date with a short format like YYYYMMDD to sort the results chronologically
    film_day_parts = film_date_long.split()
    months_list = ['januari', 'februari', 'maart',
                  'april', 'mei', 'juni', 'juli',
                  'augustus', 'september', 'oktober',
                  'november', 'december' ]
    year = str(film_day_parts[2])
    month = str(months_list.index(film_day_parts[1]) + 1).zfill(2)
    day = str(film_day_parts[0]).zfill(2)
    film_date_short = year + month + day
    for col_inner in response.xpath('//div[@class="grid__col__inner"]'):
        chnl = col_inner.xpath('.//div[@class="tv-guide__channel"]/h6/a/text()').extract_first()
        if chnl in ALLOWED_CHANNELS:
            for program in col_inner.xpath('.//div[@class="program"]'):
                item = TVGuideItem()
                item['channel'] = chnl
                item['title'] = program.xpath('.//div[@class="title"]/a/text()').extract_first()
                item['start_ts'] = program.xpath('.//div[@class="time"]/text()').extract_first()
                item['film_date_long'] = film_date_long
                item['film_date_short'] = film_date_short
                detail_link = program.xpath('.//div[@class="title"]/a/@href').extract_first()
                url_part = detail_link.rsplit('/',1)[-1]
                # Extract information from the Movie Database www.themoviedb.org
                request = scrapy.Request("https://www.themoviedb.org/search?query="+url_part,callback=self.parse_tmdb)
                request.meta['item'] = item  # Pass the item with the request to the detail page
    yield request

Скрепление дополнительной информации о базе данных фильма

Как вы можете видеть в запросе, созданном в функции parse_by_day . Мы используем функцию обратного вызова parse_tmdb Отказ Эта функция используется во время запроса, чтобы соскрести веб-сайт TMDB.

На первом шаге мы получаем информацию о предмете, которая была передана parse_by_day . функция.

Страница с результатами поиска на TMDB может перечислить несколько результатов поиска для того же заголовка фильма (URL_PART, пройденный в запросе). Мы также проверяем, есть ли результаты с Если tmddb_titles Отказ

Мы используем Fuzzywuzzy Пакет для выполнения нечетких сопоставлений на заголовки фильма. Для того, чтобы использовать пакет Fuzzywuzzy, нам нужно добавить Импорт Заявление вместе с предыдущими операторами импорта.

from fuzzywuzzy import fuzz

Если мы найдем 90% матча, мы используем этот результат поиска для выполнения остальной части соскоба. Мы больше не смотрим на другие результаты поиска. Чтобы сделать это, мы используем Перерыв утверждение.

Далее мы собираем Жанр , Рейтинг и Release_date С страницы результатов поиска аналогичным образом мы использовали функцию XPath раньше. Чтобы получить формат Yyyymmdd для даты выпуска, мы выполняем некоторые обработки данных с помощью Сплит и Присоединяйтесь к Функции.

Опять же, мы хотим запустить новый запрос на страницу сведений на TMDB. Этот запрос позвонит parse_tmdb_detail Функция для извлечения сюжета фильма и количество голосов на TMDB. Это объясняется в следующем разделе.

def parse_tmdb(self, response):
    item = response.meta['item']  # Use the passed item


    tmdb_titles = response.xpath('//a[@class="title result"]/text()').extract()
    if tmdb_titles:  # Check if there are results on TMDB
        for tmdb_title in tmdb_titles:
            match_ratio = fuzz.ratio(item['title'], tmdb_title)
            if match_ratio > 90:
                item['genre'] = response.xpath('.//span[@class="genres"]/text()').extract_first()
                item['rating'] = response.xpath('//span[@class="vote_average"]/text()').extract_first()
                release_date = response.xpath('.//span[@class="release_date"]/text()').extract_first()
                release_date_parts = release_date.split('/')
                item['release_date'] = "/".join(
                    [release_date_parts[1].strip(), release_date_parts[0].strip(), release_date_parts[2].strip()])
                tmdb_link = "https://www.themoviedb.org" + response.xpath(
                    '//a[@class="title result"]/@href').extract_first()
                item['tmdb_link'] = tmdb_link
                # Extract more info from the detail page
                request = scrapy.Request(tmdb_link, callback=self.parse_tmdb_detail)
                request.meta['item'] = item  # Pass the item with the request to the detail page
    yield request
    break  # We only consider the first match
    else:
        return

Сбор фильма с участием из страницы деталей

Последняя функция, которую мы обсудим, – это короткий. Как до того, как прежде чем мы получим пункт, передаваемый функцией PARSE_TMDB и соскрестите страницу деталей для Сюжет и Количество голосов Отказ

На этом этапе мы закончили соскобную информацию для фильма. Другими словами, предмет для фильма полностью заполнен. Затем Scrapy будет использовать код, написанный в трубопроводах для обработки этих данных и поместить его в базу данных.

def parse_tmdb_detail(self, response):
    item = response.meta['item']  # Use the passed item
    item['nb_votes'] = response.xpath('//span[@itemprop="ratingCount"]/text()').extract_first()
    item['plot'] = response.xpath('.//p[@id="overview"]/text()').extract_first()
    yield item

В разделе о трубопроводах мы уже увидели, как мы храним высказывание результатов в базе данных SQLite. Теперь я покажу вам, как вы можете Отправьте результаты соскабливания по электронной почте. Таким образом, вы получите хороший обзор лучших рейтинговых фильмов на ближайшую неделю в вашем почтовом ящике.

Импорт необходимых пакетов

Мы будем работать с файлом Extensions.py Отказ Этот файл автоматически создается в корневом каталоге при создании сценарического проекта. Мы начинаем, импортируя пакеты, которые мы будем использовать позже в этом файле.

import logging
from scrapy import signals
from scrapy.exceptions import NotConfigured
import smtplib
import sqlite3 as lite
from config import *

Регистрация Пакет на самом деле не требуется. Но этот пакет может быть полезен для отладки вашей программы или просто написать некоторую информацию в журнал. сигналы Модуль поможет нам знать, когда паук был открыт и закрыт. Мы отправим электронное письмо с фильмами после выполнения работы Spider.

От Scrapy.exceptions Модуль мы импортируем метод Неподтвержденный Отказ Это будет поднято, когда расширение не настроено в settings.py файл. Конкретно параметр Myext_enabled должен быть установлен на Правда Отказ Мы увидим это позже в коде.

smtplib Пакет импортируется, чтобы иметь возможность отправлять электронную почту. Я использую свой адрес Gmail для отправки электронной почты, но вы можете адаптировать код в config.py, чтобы использовать другую службу электронной почты.

Наконец, мы импортируем SQLite3 Пакет для извлечения верхних фильмов из базы данных и импорта config . чтобы получить наши константы.

Создание класса Sendemail в расширении

Во-первых, мы определяем регистратор объект. С помощью этого объекта мы можем писать сообщения в журнал на определенные события. Тогда мы создаем Sendemail Класс с методом конструктора. В конструкторе мы назначаем Fromaddr и Тоддр к соответствующим атрибутам класса. Эти константы устанавливаются в config.py . файл. Я использовал свой адрес Gmail для обоих атрибутов.

logger = logging.getLogger(__name__)
class SendEmail(object):
    def __init__(self):
        self.fromaddr = FROMADDR
        self.toaddr  = TOADDR

Расположенный объект расширения

Первый метод Sendemail Объект это from_crawler Отказ Первый чек мы делаем, есть ли Myext_enabled включается в файле settings.py. Если это не так, мы поднимаем Неподтвержденный исключение. Когда это произойдет, остальная часть кода в расширении не выполняется.

В settings.py Файл, который нам нужно добавить следующий код, чтобы включить это расширение.

MYEXT_ENABLED = True
EXTENSIONS = {
    'topfilms.extensions.SendEmail': 500,
    'scrapy.telnet.TelnetConsole': None
}

Итак, мы устанавливаем логический флаг Myext_enabled к Правда Отказ Затем мы добавляем наше собственное расширение Sendemail к Расширения Словарь. Целочисленное значение 500 указывает порядок, в котором необходимо выполнить расширение. Я также должен был отключить TelnetConsole Отказ В противном случае отправка электронной почты не работает. Это расширение отключено, поместив Нет вместо целочисленного значения заказа.

Далее мы создали объект расширения с CLS () функция. Для этого объекта расширения мы подключаем некоторые сигналы Отказ Мы заинтересованы в Spider_opened и Spider_Closed сигналы. И, наконец, мы возвращаем Ext объект.

@classmethod
def from_crawler(cls, crawler):
    # first check if the extension should be enabled and raise
    # NotConfigured otherwise
    if not crawler.settings.getbool('MYEXT_ENABLED'):
        raise NotConfigured
    # instantiate the extension object
    ext = cls()
    # connect the extension object to signals
    crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
    crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
    # return the extension object
    return ext

Определите действия в событии Spider_Oped

Когда паук был открыт, мы просто хотим написать это в журнал. Поэтому мы используем регистратор объект, который мы создали в верхней части кода. С Информация Метод мы пишем сообщение в журнал. Spider.name заменяется на имя, которое мы определили в файле TVGuidesPider.py.

def spider_opened(self, spider):
    logger.info("opened spider %s", spider.name)

Отправка электронного письма после события Spider_Cloed

В последнем методе Sendemail Класс Мы отправляем электронное письмо, содержащее обзор с лучшими номинальными фильмами.

Опять же, мы отправляем уведомление в журнал, который паук был закрыт. Во-вторых, мы создаем соединение с базой данных SQLite, содержащей все фильмы предстоящей недели для Разрешен_channels. Мы выбираем фильмы с Рейтинг.5 Отказ Вы можете изменить рейтинг на более высокий или нижний порог, сколько пожелаете. Полученные пленки затем отсортированы по film_date_short , который имеет формат yyymmdd и в начале времени start_ts Отказ

Мы принесем все строки в курсоре Cur и проверьте, есть ли у нас некоторые результаты с Лен функция. Можно не иметь результатов, когда вы устанавливаете пороговый рейтинг слишком высоки, например.

С для строки в данных Мы проходим через каждую полученную пленку. Мы извлекаем всю интересную информацию от ряд Отказ Для некоторых данных мы применяем некоторую кодировку с кодировать («ASCII», «игнорировать») Отказ Это игнорировать некоторые специальные символы, такие как É, À, è, и так далее. В противном случае мы получаем ошибки при отправке электронной почты.

Когда все данные о фильме собираются, мы составляем строковую переменную Topfilm Отказ Каждый Topfilm затем объединяется на переменную topfilms_overview , что будет сообщение электронной почты, которую мы отправляем. Если у нас нет фильма в нашем результате запроса, мы упоминаем об этом в коротком послании.

В конце мы отправляем сообщение с адресом Gmail, благодаря smtplib упаковка.

def spider_closed(self, spider):
    logger.info("closed spider %s", spider.name)
    # Getting films with a rating above a threshold
    topfilms_overview = ""
    con = lite.connect('topfilms.db')
    cur = con.execute(
        "SELECT title, channel, start_ts, film_date_long, plot, genre, release_date, rating, tmdb_link, nb_votes "
        "FROM topfilms "
        "WHERE rating >= 6.5 "
        "ORDER BY film_date_short, start_ts")


    data = cur.fetchall()
    if len(data) > 0:  # Check if we have records in the query result
        for row in data:
            title = row[0].encode('ascii', 'ignore')
            channel = row[1]
            start_ts = row[2]
            film_date_long = row[3]
            plot = row[4].encode('ascii', 'ignore')
            genre = row[5]
            release_date = row[6].rstrip()
            rating = row[7]
            tmdb_link = row[8]
            nb_votes = row[9]
            topfilm = ' - '.join([title, channel, film_date_long, start_ts])
            topfilm = topfilm + "\r\n" + "Release date: " + release_date
            topfilm = topfilm + "\r\n" + "Genre: " + str(genre)
            topfilm = topfilm + "\r\n" + "TMDB rating: " + rating + " from " + nb_votes + " votes"
            topfilm = topfilm + "\r\n" + plot
            topfilm = topfilm + "\r\n" + "More info on: " + tmdb_link
            topfilms_overview = "\r\n\r\n".join([topfilms_overview, topfilm])
    con.close()
    if len(topfilms_overview) > 0:
        message = topfilms_overview
    else:
        message = "There are no top rated films for the coming week."
    msg = "\r\n".join([
        "From: " + self.fromaddr,
        "To: " + self.toaddr,
        "Subject: Top Films Overview",
        message
    ])
    username = UNAME
    password = PW
    server = smtplib.SMTP(GMAIL)
    server.ehlo()
    server.starttls()
    server.login(username, password)
    server.sendmail(self.fromaddr, self.toaddr, msg)
    server.quit()

Результат отправки электронных писем через расширения

Окончательный результат этого кода является обзор с верхним номинальным фильмами в вашем почтовом ящике. Большой! Теперь вам больше не нужно искать это в онлайн-телевидении.

Когда вы делаете много запросов за короткий промежуток времени, вы рискуете запрещать сервером. В этом финальном разделе я покажу вам какие-то трюки, чтобы избежать запрета IP.

Задержка ваших запросов

Один простой способ избежать IP Banning – это Пауза между каждым запросом Отказ В Scrapy это можно сделать, просто установив параметр в settings.py файл. Как вы, вероятно, заметили, файл settings.py имеет много параметров, прокомментированных.

Поиск параметра Download_delay И вотворить это. Я установил Длина паузы до 2 секунд Отказ В зависимости от того, сколько запросов вы должны сделать, вы можете изменить это. Но я бы поставил его по крайней мере 1 секунду.

DOWNLOAD_DELAY=2

Более продвинутый способ избежать запрета IP

По умолчанию каждый раз, когда вы делаете запрос, вы делаете это с тот же пользовательский агент Отказ Благодаря пакету fake_useragent Мы можем легко изменить пользовательский агент для каждого запроса.

Все кредиты для этого куска кода отправляются в Alecxe Кто написал хороший сценарий Python, чтобы использовать пакет FAKE_USERAGENT.

Во-первых, мы создаем папку scrapy_fake_useragent В корневом каталоге нашего веб-скребка проекта. В этой папке мы добавляем два файла:

  • __init__.py который является пустым файлом
  • middleware.py

Использовать это промежуточное программное обеспечение Нам нужно включить его в settings.py файл. Это сделано с кодом:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
    'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400,
}

Во-первых, мы отключаем по умолчанию Useragentmiddleware Scrapy, указав Нет вместо целочисленного значения. Тогда мы включаем наши собственные промежуточные программы RentalUserAgentMiddleware Отказ Интуитивно промежуточное ПО – это кусок кода, который выполнен Во время запроса Отказ

В файле Middleware.py Мы добавляем код на Randomize пользовательский агент для каждого запроса. Убедитесь, что у вас установлен пакет Fake_userAgent. От Fake_usergent Package Мы импортируем Useragent модуль. Это содержит Список различных пользовательских агентов Отказ В конструкторе класса RenderUserAgentMiddleware мы создали объект useragent. В методе Process_request Мы устанавливаем агент пользователя случайному агенту пользователя из UA объект в заголовке запроса.

from fake_useragent import UserAgent
class RandomUserAgentMiddleware(object):
    def __init__(self):
        super(RandomUserAgentMiddleware, self).__init__()
        self.ua = UserAgent()
    def process_request(self, request, spider):
        request.headers.setdefault('User-Agent', self.ua.random)

Это было! Я надеюсь, что у вас теперь есть четкий представление о том, как использовать SCRAPY для ваших веб-проектов Scraping.