예제 #1
0
class AvitoAdParser(QObject):
    """Парсер страницы объявления сайта avito.ru"""

    def __init__(self):
        super().__init__()

        self.app = QApplication(sys.argv)

        QNetworkProxyFactory.setUseSystemConfiguration(True)

        self.web_page = QWebPage(self)
        self.web_page.settings().setAttribute(QWebSettings.AutoLoadImages, False)
        self.web_page.loadFinished.connect(self.load_finished)

        # Адрес страницы объявления
        self.url = None

        # Переменная нужна для замера времени выполнения
        self.t = None

        self.phone_img_parser = AvitoPhoneImgParser()

        # Строка с номером телефона
        self.phone = None

        self.proxy_url = None
        self.proxy_type = None
        self.proxy_enabled = None

    # Сигнал вызывается, когда закончен парсинг сотового из объявления
    parse_phone_finished = Signal(str)

    def run(self, url):
        """Функция выполняет парсинг страницы объявления"""

        self.url = url
        self.phone = None

        self.t = time.clock()

        # Загружаем страницу объявления
        self.web_page.mainFrame().load(url)

        logger.debug('Начало выполнения загрузки "{}" {:.3f} секунд'.format(url, time.clock() - self.t))

        # Ждем тут, пока закончится парсинг объявления -- все из-за ассинхронности webpage и моей лени -- хочется
        # просто в цикле запустить обработку и url, но из-за асинхронности с сигналами это не сработает -- какая-то
        # лажа происходит -- падает приложение с ошибкой где-то в QtCore.dll
        loop = QEventLoop()
        self.parse_phone_finished.connect(loop.quit)
        loop.exec_()

        logger.debug('Время выполнения парсера {:.3f} секунд'.format(time.clock() - self.t))
        self.t = None

    def get_phone(self):
        """Функция выполняет поиск картинки с номером телефона, получает его адрес, скачивает, а после
        парсит картинку с номером и записывает в self.phone номер телефона. После парсинга вызывает сигнал
        parse_phone_finished, в котором передается номер телефона.

        """

        # Ищем элемент с картинкой телефона
        el = self.web_page.mainFrame().findFirstElement("img[class='description__phone-img']")

        logger.debug('Поиск изображения телефона {:.3f} секунд'.format(time.clock() - self.t))

        ok = not el.isNull()
        if ok:
            src = el.attribute('src')
            logger.debug('Атрибут src картинки с телефоном: "%s".', src)
            src = src.replace('data:image/png;base64,', '')
            logger.debug('Данные картинки с телефоном: "%s".', src)
            data = base64.b64decode(src)

            # TODO: вызывать исключение, если номер не найден
            # TODO: вызывать исключение, если номер не 11 символов (нормальный номер: 89615750404)
            phone_number = self.phone_img_parser.parse_from_data(data)
            logger.debug('Телефон получен: %s', phone_number)
            logger.debug('Парсинг номера телефона из картинки {:.3f} секунд'.format(time.clock() - self.t))

            self.phone = phone_number
            self.parse_phone_finished.emit(phone_number)

    def find_and_click_element(self):
        """Функция ищет на странице объявления элемент 'Показать телефон' и кликает его, чтобы
        выполнились страшные скрипты и загрузилась картинка с номером телефона

        """

        code = """
        span_phone = $("span[class='description__phone-insert js-phone-show__insert'] span[class='btn__text']")
        span_phone.click()
        """

        logger.debug('Выполняю программный клик по кнопке "Получить телефон"')
        ok = self.web_page.mainFrame().evaluateJavaScript(code)
        if ok is None:
            logger.warn('Выполнение js скрипта неудачно. Code:\n%s', code)
            return

        logger.debug('Время выполнения js скрипта {:.3f} секунд'.format(time.clock() - self.t))
        self.get_phone()

    def load_finished(self, x):
        """Функция вызывается, когда QWebView отсылает сигнал loadFinished"""

        if x and self.phone is None:
            logger.info('Загрузка завершена {:.3f} секунд'.format(time.clock() - self.t))
            self.find_and_click_element()
예제 #2
0
class AvitoAdParser(QObject):
    """Парсер страницы объявления сайта avito.ru"""
    def __init__(self):
        super().__init__()

        self.app = QApplication(sys.argv)

        QNetworkProxyFactory.setUseSystemConfiguration(True)

        self.web_page = QWebPage(self)
        self.web_page.settings().setAttribute(QWebSettings.AutoLoadImages,
                                              False)
        self.web_page.loadFinished.connect(self.load_finished)

        # Адрес страницы объявления
        self.url = None

        # Переменная нужна для замера времени выполнения
        self.t = None

        self.phone_img_parser = AvitoPhoneImgParser()

        # Строка с номером телефона
        self.phone = None

        self.proxy_url = None
        self.proxy_type = None
        self.proxy_enabled = None

    # Сигнал вызывается, когда закончен парсинг сотового из объявления
    parse_phone_finished = Signal(str)

    def run(self, url):
        """Функция выполняет парсинг страницы объявления"""

        self.url = url
        self.phone = None

        self.t = time.clock()

        # Загружаем страницу объявления
        self.web_page.mainFrame().load(url)

        logger.debug('Начало выполнения загрузки "{}" {:.3f} секунд'.format(
            url,
            time.clock() - self.t))

        # Ждем тут, пока закончится парсинг объявления -- все из-за ассинхронности webpage и моей лени -- хочется
        # просто в цикле запустить обработку и url, но из-за асинхронности с сигналами это не сработает -- какая-то
        # лажа происходит -- падает приложение с ошибкой где-то в QtCore.dll
        loop = QEventLoop()
        self.parse_phone_finished.connect(loop.quit)
        loop.exec_()

        logger.debug(
            'Время выполнения парсера {:.3f} секунд'.format(time.clock() -
                                                            self.t))
        self.t = None

    def get_phone(self):
        """Функция выполняет поиск картинки с номером телефона, получает его адрес, скачивает, а после
        парсит картинку с номером и записывает в self.phone номер телефона. После парсинга вызывает сигнал
        parse_phone_finished, в котором передается номер телефона.

        """

        # Ищем элемент с картинкой телефона
        el = self.web_page.mainFrame().findFirstElement(
            "img[class='description__phone-img']")

        logger.debug(
            'Поиск изображения телефона {:.3f} секунд'.format(time.clock() -
                                                              self.t))

        ok = not el.isNull()
        if ok:
            src = el.attribute('src')
            logger.debug('Атрибут src картинки с телефоном: "%s".', src)
            src = src.replace('data:image/png;base64,', '')
            logger.debug('Данные картинки с телефоном: "%s".', src)
            data = base64.b64decode(src)

            # TODO: вызывать исключение, если номер не найден
            # TODO: вызывать исключение, если номер не 11 символов (нормальный номер: 89615750404)
            phone_number = self.phone_img_parser.parse_from_data(data)
            logger.debug('Телефон получен: %s', phone_number)
            logger.debug(
                'Парсинг номера телефона из картинки {:.3f} секунд'.format(
                    time.clock() - self.t))

            self.phone = phone_number
            self.parse_phone_finished.emit(phone_number)

    def find_and_click_element(self):
        """Функция ищет на странице объявления элемент 'Показать телефон' и кликает его, чтобы
        выполнились страшные скрипты и загрузилась картинка с номером телефона

        """

        code = """
        span_phone = $("span[class='description__phone-insert js-phone-show__insert'] span[class='btn__text']")
        span_phone.click()
        """

        logger.debug('Выполняю программный клик по кнопке "Получить телефон"')
        ok = self.web_page.mainFrame().evaluateJavaScript(code)
        if ok is None:
            logger.warn('Выполнение js скрипта неудачно. Code:\n%s', code)
            return

        logger.debug(
            'Время выполнения js скрипта {:.3f} секунд'.format(time.clock() -
                                                               self.t))
        self.get_phone()

    def load_finished(self, x):
        """Функция вызывается, когда QWebView отсылает сигнал loadFinished"""

        if x and self.phone is None:
            logger.info(
                'Загрузка завершена {:.3f} секунд'.format(time.clock() -
                                                          self.t))
            self.find_and_click_element()