Esempio n. 1
0
File: parser.py Progetto: R0nd/dr-tg
    def __init__(self):
        self.g = Grab()
        self.g.setup(timeout=100)
        self.db = dataset.connect(settings.DATASET)

        self.table_code = self.db['code']
        self.table_sector = self.db['sector']
        self.table_tip = self.db['tip']
        self.table_cookies = self.db['cookies']
        self.table_bot = self.db['bot']

        current_bot = self.table_bot.find_one(**{'token': settings.TOKEN})
        if current_bot is None:
            self.table_bot.insert({
                'token': settings.TOKEN,
                'level': None,
                'spoiler': False,
            })

        for cookie_dict in self.db['cookies']:
            del cookie_dict['id']
            try:
                self.g.cookies.set(**cookie_dict)
            except ValueError:
                pass
Esempio n. 2
0
 def create_grab_instance(self, **kwargs):
     # Back-ward compatibility for deprecated `grab_config` attribute
     # Use _grab_config to not trigger warning messages
     if self._grab_config and kwargs:
         merged_config = deepcopy(self._grab_config)
         merged_config.update(kwargs)
         return Grab(**merged_config)
     elif self._grab_config and not kwargs:
         return Grab(**self._grab_config)
     else:
         return Grab(**kwargs)
Esempio n. 3
0
 def create_grab_instance(self, **kwargs):
     # Back-ward compatibility for deprecated `grab_config` attribute
     # Here I use `_grab_config` to not trigger warning messages
     kwargs['transport'] = self.grab_transport_name
     if self._grab_config and kwargs:
         merged_config = deepcopy(self._grab_config)
         merged_config.update(kwargs)
         grab = Grab(**merged_config)
     elif self._grab_config and not kwargs:
         grab = Grab(**self._grab_config)
     else:
         grab = Grab(**kwargs)
     return grab
Esempio n. 4
0
    def __init__(self):
        self.g = Grab()
        self.g.setup(timeout=100)
        self.db = dataset.connect(settings.DATASET)

        self.table_code = self.db['code']
        self.table_sector = self.db['sector']
        self.table_tip = self.db['tip']
        self.table_cookies = self.db['cookies']
        self.table_bot = self.db['bot']

        if self.table_bot.find_one(**{'token': settings.TOKEN}) is None:
            self.table_bot.insert({
                'token': settings.TOKEN,
                'level': None,
                'spoiler': False,
            })

        for cookie_dict in self.db['cookies']:
            del cookie_dict['id']
            try:
                self.g.cookies.set(**cookie_dict)
            except ValueError:
                pass
Esempio n. 5
0
class Parser(object):
    write_log_files = False

    def __init__(self):
        self.g = Grab()
        self.g.setup(timeout=100)
        self.db = dataset.connect(settings.DATASET)

        self.table_code = self.db['code']
        self.table_sector = self.db['sector']
        self.table_tip = self.db['tip']
        self.table_cookies = self.db['cookies']
        self.table_bot = self.db['bot']

        if self.table_bot.find_one(**{'token': settings.TOKEN}) is None:
            self.table_bot.insert({
                'token': settings.TOKEN,
                'level': None,
                'spoiler': False,
            })

        for cookie_dict in self.db['cookies']:
            del cookie_dict['id']
            try:
                self.g.cookies.set(**cookie_dict)
            except ValueError:
                pass

    def set_cookie(self, cookie):
        self.g.cookies.set(
            name='dozorSiteSession',
            value=cookie,
            domain='.dzzzr.ru',
            path='/',
        )

    def auth(self, login, password):
        """Авторизация на сайте дозора"""
        self.table_cookies.delete()

        self.g.go(auth_url)
        if not (self.g.doc.select(b'.//*[@name="login"]').exists()
                and self.g.doc.select(b'.//*[@name="password"]').exists()):
            return False
        self.g.doc.set_input('login', login)
        self.g.doc.set_input('password', password)
        self.g.doc.submit()
        html = self.g.doc.body.decode('cp1251')
        if 'Ошибка авторизации' in html:
            return False
        cookie_list = self.g.cookies.get_dict()

        for cookie_dict in cookie_list:
            self.table_cookies.insert(cookie_dict)
        return True

    def set_pin(self, userpwd):
        self.g.setup(userpwd=userpwd)

    @throttle(seconds=2)
    def fetch(self, code=None):
        """Загружает страницу движка"""
        n = datetime.utcnow()

        self.g.go(main_url)
        if code is not None:
            if self.g.doc.select(b'.//*[@name="cod"]').exists():
                self.g.doc.set_input('cod', code)
                self.g.doc.submit()

        if self.write_log_files:
            dir_1 = "./log/{}".format(n.strftime("%H"))
            dir_2 = "{}/{}".format(dir_1, n.strftime("%H_%M"))
            filepath = "{}/log_{}.html".format(dir_2, n.strftime("%H_%M_%S"))
            if not os.path.exists('./log'):
                os.makedirs('./log')
            if not os.path.exists(dir_1):
                os.makedirs(dir_1)
            if not os.path.exists(dir_2):
                os.makedirs(dir_2)
            with codecs.open(filepath, mode='w+', encoding='utf-8') as f:
                html = self.g.doc.body.decode('cp1251')
                f.write(html)

    def parse(self):
        result = {}
        result.update(self._parse_level())
        result.update(self._parse_tip())
        result.update(self._parse_spoiler())
        result.update(self._parse_message())
        result.update(self._parse_clock())
        return result

    def _parse_message(self):
        if not self.g.doc.select('//div[@class="sysmsg"]//b').exists():
            return {'message': ''}
        message = self.g.doc.select('//div[@class="sysmsg"]//b').html()
        message = message.replace('<b>', '').replace('</b>', '').strip()
        return {'message': message}

    def _parse_clock(self):
        for script_el in self.g.doc.select('//table//tr//td//script'):
            for seconds in re.findall('setTimeout\(\'countDown\((\d+)\)\',',
                                      script_el.html(),
                                      flags=re.I):
                try:
                    seconds = int(seconds)
                except TypeError:
                    continue
                t = time.gmtime(seconds)
                time_pattern = "%H:%M:%S" if seconds > 60 * 60 else "%M:%S"
                result = {'clock': time.strftime(time_pattern, t)}
                return result
        return {}

    def _parse_level(self):
        """
        Парсит страницу дозорного движка. Возвращает словарь с инфой об обновлении.
        Подробнее, что такое инфа обновления - в комментариях ниже
        """
        result = {
            'new_level': False,  # Новый уровень?
            'new_code': False,  # Новый пробитый код?
            'new_metki':
            [],  # Номер (или возможные номера) пробитых кодов, если есть
            'sector_list': [],  # Инфо о взятых кодах
        }
        try:
            div = self.g.doc.select('//div[@class="zad"][1]')[0]
        except IndexError:
            return result
        sector_list_str = div.html()

        html = self.g.doc.body.decode('cp1251')

        level_number_list = list(re.findall(
            'levelNumberBegin-->(\d+)\<', html)) + list(
                re.findall('Задание (\d+)', html))
        if level_number_list:
            level = int(level_number_list[0])
        else:
            level = 0

        bot_data = self.table_bot.find_one(**{'token': settings.TOKEN})

        if bot_data.get('level') is None or int(
                bot_data.get('level')) != level:
            self.table_bot.upsert(
                {
                    'token': settings.TOKEN,
                    'level': level,
                    'spoiler': False,
                }, ['token'])
            self.table_sector.delete()
            self.table_code.delete()
            self.table_tip.delete()
            result['new_level'] = True

        try:
            sector_list_str = sector_list_str.split(
                '<strong>Коды сложности</strong><br>')[1]
        except IndexError:
            return result
        sector_list_str = sector_list_str.split('</div>')[0]
        sector_list_str = sector_list_str.replace('null', 'N')
        for sector_index, sector_str in enumerate(
                sector_list_str.split('<br>')):
            sector_str = sector_str.strip()
            # Сектор основные коды: 1+, 2+, 2+
            #  основные коды: 1+, 2+, 2+
            sector_parts = sector_str.split(': ')
            if len(sector_parts) < 2:
                continue
            sector_name = ': '.join(
                i.strip() for i in sector_parts[:-1]).replace('Сектор ', '')
            sector_code_str = sector_parts[-1]
            sector = {
                'id': sector_index + 1,
                'name': sector_name.strip(),
                'code_list': [],
            }
            for metka_index, item in enumerate(sector_code_str.split(', ')):
                taken = bool(red_span_re.match(item))
                ko = red_span_re.findall(item)[0][0] if taken else item

                old_code = self.table_code.find_one(
                    **{
                        'sector_id': sector_index + 1,
                        'metka': metka_index + 1,
                    })
                filters = {
                    'ko': ko,
                    'taken': taken,
                    'metka': metka_index + 1,
                    'sector_id': sector_index + 1,
                }
                if old_code is None:
                    self.table_code.insert(filters)
                elif old_code['taken'] != taken:
                    self.table_code.update(filters, ['sector_id', 'metka'])
                    if not (bot_data.get('dont_notify_bonus')
                            and 'бонусные коды' in sector['name']):
                        result['new_code'] = True
                    sector['code_list'].append(filters)
                    result['new_metki'].append(
                        dict(sector_name=sector['name'],
                             metka=filters['metka']))

            result['sector_list'].append(sector)
            self.table_sector.upsert(
                {
                    'id': sector_index + 1,
                    'name': sector_name,
                }, ['id'])
        return result

    def _parse_tip(self):
        """
        Парсит текст подсказок. Возвращает объект обновления
        """
        result = {
            'tip_list': [],  # Новые подсказки.
        }

        div_list = self.g.doc.select('//div[@class="title"]')

        for div in div_list:
            for tip_title, tip_index in (
                (
                    'Подсказка l:', 1
                ),  # здесь нет опечатки, в дозором движке используется именно латинская буква l вместо цифры 1.
                ('Подсказка 2:', 2),
            ):
                if tip_title in div.html():
                    tip_node = div.node().getnext()
                    for br in tip_node.xpath("*//br"):
                        br.tail = "\n" + br.tail if br.tail else "\n"
                    tip_text = tip_node.text_content()
                    if 'не предусмотрена' in tip_text.lower():
                        continue
                    old_tip = self.table_tip.find_one(index=tip_index)
                    self.table_tip.upsert(
                        {
                            'text': tip_text,
                            'index': tip_index,  # номер подсказки
                        },
                        ['index'])
                    if old_tip is None:
                        result['tip_list'].append({
                            'text': tip_text,
                            'index': tip_index,
                        })
        return result

    def _parse_spoiler(self):
        """
        Парсит текст спойлера. Возвращает объект обновления
        """
        result = {
            'new_spoiler': False,  # Новый открытый спойлер?
        }

        bot_data = self.table_bot.find_one(**{'token': settings.TOKEN})

        if bot_data.get('spoiler'):
            return result

        try:
            level_div = self.g.doc.select('//div[@class="zad"][1]')[0]
        except IndexError:
            return result

        level_html = level_div.html()
        if '<div class="title" style="padding-left:0">Спойлер</div>' in level_html:
            result['new_spoiler'] = True
            self.table_bot.upsert({
                'token': settings.TOKEN,
                'spoiler': True,
            }, ['token'])

        return result
Esempio n. 6
0
class Parser(object):
    write_log_files = False

    def __init__(self):
        self.g = Grab()
        self.g.setup(timeout=100)
        self.db = dataset.connect(settings.DATASET)

        self.table_code = self.db['code']
        self.table_sector = self.db['sector']
        self.table_tip = self.db['tip']
        self.table_cookies = self.db['cookies']
        self.table_bot = self.db['bot']

        if self.table_bot.find_one(**{'token': settings.TOKEN}) is None:
            self.table_bot.insert({
                'token': settings.TOKEN,
                'level': None,
                'spoiler': False,
            })

        for cookie_dict in self.db['cookies']:
            del cookie_dict['id']
            try:
                self.g.cookies.set(**cookie_dict)
            except ValueError:
                pass

    def set_cookie(self, cookie):
        self.g.cookies.set(
            name='dozorSiteSession',
            value=cookie,
            domain='.dzzzr.ru',
            path='/',
        )

    def auth(self, login, password):
        """Авторизация на сайте дозора"""
        self.table_cookies.delete()

        self.g.go(auth_url)
        if not (self.g.doc.select(b'.//*[@name="login"]').exists() and self.g.doc.select(b'.//*[@name="password"]').exists()):
            return False
        self.g.doc.set_input('login', login)
        self.g.doc.set_input('password', password)
        self.g.doc.submit()
        html = self.g.doc.body.decode('cp1251')
        if 'Ошибка авторизации' in html:
            return False
        cookie_list = self.g.cookies.get_dict()

        for cookie_dict in cookie_list:
            self.table_cookies.insert(cookie_dict)
        return True

    def set_pin(self, userpwd):
        self.g.setup(userpwd=userpwd)

    @throttle(seconds=2)
    def fetch(self, code=None):
        """Загружает страницу движка"""
        n = datetime.utcnow()

        self.g.go(main_url)
        if code is not None:
            if self.g.doc.select(b'.//*[@name="cod"]').exists():
                self.g.doc.set_input('cod', code)
                self.g.doc.submit()

        if self.write_log_files:
            dir_1 = "./log/{}".format(n.strftime("%H"))
            dir_2 = "{}/{}".format(dir_1, n.strftime("%H_%M"))
            filepath = "{}/log_{}.html".format(dir_2, n.strftime("%H_%M_%S"))
            if not os.path.exists('./log'):
                os.makedirs('./log')
            if not os.path.exists(dir_1):
                os.makedirs(dir_1)
            if not os.path.exists(dir_2):
                os.makedirs(dir_2)
            with codecs.open(filepath, mode='w+', encoding='utf-8') as f:
                html = self.g.doc.body.decode('cp1251')
                f.write(html)

    def parse(self):
        result = {}
        result.update(self._parse_level())
        result.update(self._parse_tip())
        result.update(self._parse_spoiler())
        result.update(self._parse_message())
        result.update(self._parse_clock())
        return result

    def _parse_message(self):
        if not self.g.doc.select('//div[@class="sysmsg"]//b').exists():
            return {
                'message': ''
            }
        message = self.g.doc.select('//div[@class="sysmsg"]//b').html()
        message = message.replace('<b>', '').replace('</b>', '').strip()
        return {
            'message': message
        }

    def _parse_clock(self):
        for script_el in self.g.doc.select('//table//tr//td//script'):
            for seconds in re.findall('setTimeout\(\'countDown\((\d+)\)\',', script_el.html(), flags=re.I):
                try:
                    seconds = int(seconds)
                except TypeError:
                    continue
                t = time.gmtime(seconds)
                time_pattern = "%H:%M:%S" if seconds > 60*60 else "%M:%S"
                result = {
                    'clock': time.strftime(time_pattern, t)
                }
                return result
        return {}

    def _parse_level(self):
        """
        Парсит страницу дозорного движка. Возвращает словарь с инфой об обновлении.
        Подробнее, что такое инфа обновления - в комментариях ниже
        """
        result = {
            'new_level': False,  # Новый уровень?
            'new_code': False,  # Новый пробитый код?
            'new_metki': [],  # Номер (или возможные номера) пробитых кодов, если есть
            'sector_list': [],  # Инфо о взятых кодах
        }
        try:
            div = self.g.doc.select('//div[@class="zad"][1]')[0]
        except IndexError:
            return result
        sector_list_str = div.html()

        html = self.g.doc.body.decode('cp1251')

        level_number_list = list(re.findall('levelNumberBegin-->(\d+)\<', html)) + list(re.findall('Задание (\d+)', html))
        if level_number_list:
            level = int(level_number_list[0])
        else:
            level = 0

        bot_data = self.table_bot.find_one(**{'token': settings.TOKEN})

        if bot_data.get('level') is None or int(bot_data.get('level')) != level:
            self.table_bot.upsert({
                'token': settings.TOKEN,
                'level': level,
                'spoiler': False,
            }, ['token'])
            self.table_sector.delete()
            self.table_code.delete()
            self.table_tip.delete()
            result['new_level'] = True

        try:
            sector_list_str = sector_list_str.split('<strong>Коды сложности</strong><br>')[1]
        except IndexError:
            return result
        sector_list_str = sector_list_str.split('</div>')[0]
        sector_list_str = sector_list_str.replace('null', 'N')
        for sector_index, sector_str in enumerate(sector_list_str.split('<br>')):
            sector_str = sector_str.strip()
            # Сектор основные коды: 1+, 2+, 2+
            #  основные коды: 1+, 2+, 2+
            sector_parts = sector_str.split(': ')
            if len(sector_parts) < 2:
                continue
            sector_name = ': '.join(i.strip() for i in sector_parts[:-1]).replace('Сектор ', '')
            sector_code_str = sector_parts[-1]
            sector = {
                'id': sector_index + 1,
                'name': sector_name.strip(),
                'code_list': [],
            }
            for metka_index, item in enumerate(sector_code_str.split(', ')):
                taken = bool(red_span_re.match(item))
                ko = red_span_re.findall(item)[0][0] if taken else item

                old_code = self.table_code.find_one(**{
                    'sector_id': sector_index + 1,
                    'metka': metka_index + 1,
                })
                filters = {
                    'ko': ko,
                    'taken': taken,
                    'metka': metka_index + 1,
                    'sector_id': sector_index + 1,
                }
                if old_code is None:
                    self.table_code.insert(filters)
                elif old_code['taken'] != taken:
                    self.table_code.update(filters, ['sector_id', 'metka'])
                    if not(bot_data.get('dont_notify_bonus') and 'бонусные коды' in sector['name']):
                        result['new_code'] = True
                    sector['code_list'].append(filters)
                    result['new_metki'].append(dict(sector_name=sector['name'], metka=filters['metka']))

            result['sector_list'].append(sector)
            self.table_sector.upsert({
                'id': sector_index + 1,
                'name': sector_name,
            }, ['id'])
        return result

    def _parse_tip(self):
        """
        Парсит текст подсказок. Возвращает объект обновления
        """
        result = {
            'tip_list': [],  # Новые подсказки.
        }

        div_list = self.g.doc.select('//div[@class="title"]')

        for div in div_list:
            for tip_title, tip_index in (
                ('Подсказка l:', 1),  # здесь нет опечатки, в дозором движке используется именно латинская буква l вместо цифры 1.
                ('Подсказка 2:', 2),
            ):
                if tip_title in div.html():
                    tip_node = div.node().getnext()
                    for br in tip_node.xpath("*//br"):
                        br.tail = "\n" + br.tail if br.tail else "\n"
                    tip_text = tip_node.text_content()
                    if 'не предусмотрена' in tip_text.lower():
                        continue
                    old_tip = self.table_tip.find_one(index=tip_index)
                    self.table_tip.upsert({
                        'text': tip_text,
                        'index': tip_index,  # номер подсказки
                    }, ['index'])
                    if old_tip is None:
                        result['tip_list'].append({
                            'text': tip_text,
                            'index': tip_index,
                        })
        return result

    def _parse_spoiler(self):
        """
        Парсит текст спойлера. Возвращает объект обновления
        """
        result = {
            'new_spoiler': False,  # Новый открытый спойлер?
        }

        bot_data = self.table_bot.find_one(**{'token': settings.TOKEN})

        if bot_data.get('spoiler'):
            return result

        try:
            level_div = self.g.doc.select('//div[@class="zad"][1]')[0]
        except IndexError:
            return result

        level_html = level_div.html()
        if '<div class="title" style="padding-left:0">Спойлер</div>' in level_html:
            result['new_spoiler'] = True
            self.table_bot.upsert({
                'token': settings.TOKEN,
                'spoiler': True,
            }, ['token'])

        return result
Esempio n. 7
0
 def create_grab_instance(self):
     #构建实例
     return Grab()