Ensina como usar a estrutura Scrapy crawler para rastrear os dados do fórum de alimentos e armazená-los no banco de dados

    Olá a todos, é a primeira vez que escrevo um artigo sobre esse tipo de projeto de compartilhamento. Pode ser muito aguado e incompleto, e deve haver alguns erros. Espero que vocês possam dar dicas nos comentários. Obrigado!

I. Introdução

Um rastreador da web (também conhecido como web spider ou robô da web) é um programa ou script que rastreia automaticamente informações na World Wide Web de acordo com certas regras. Outros nomes menos usados ​​são formigas, indexação automática, simuladores ou vermes. ------ Baidu Encyclopedia

    Em termos humanos, os crawlers são usados ​​para obter grandes quantidades de dados de maneira regular e, em seguida, processá-los e usá-los. É uma das condições de suporte necessárias em big data, finanças, aprendizado de máquina e assim por diante.

    Atualmente, nas cidades de primeiro nível, o salário e o tratamento dos rastreadores são relativamente objetivos.A promoção posterior a engenheiros de rastreadores de nível médio e sênior, analistas de dados e cargos de desenvolvimento de big data são boas transições.

 

2. Metas do projeto

    O projeto apresentado aqui não precisa ser muito complicado.O objetivo final é rastrear cada comentário da postagem no banco de dados e atualizar os dados, evitar rastreamento repetido, anti-rastreamento e outras medidas.

 

3. Preparação do projeto

Esta parte apresenta principalmente as ferramentas usadas neste artigo, as bibliotecas envolvidas, páginas da web e outras informações, etc.

Software: PyCharm

Bibliotecas necessárias: Scrapy, selenium, pymongo, user_agent, datetime

Site de destino:

http://bbs.foodmate.net

Plug-in: chromedriver (a versão deve estar correta)

 

Quatro, análise do projeto

1. Determine a estrutura do site de rastreamento

    Resumindo: determine o método de carregamento do site, como inserir corretamente a postagem para obter os dados nível por nível, qual formato usar para salvar os dados, etc.

    Em segundo lugar, observe a estrutura hierárquica do site, ou seja, como entrar na página de postagem aos poucos de acordo com as seções, isso é muito importante para essa tarefa do crawler, e também é a parte principal da escrita do código.

 

2. Como escolher a maneira correta de rastrear dados?

    Atualmente, os métodos do rastreador que conheço são os seguintes (incompletos, mas mais comumente usados):

    1) Estrutura de solicitação: Esta biblioteca http pode ser usada para rastrear os dados necessários de maneira flexível, simples, mas o processo é um pouco complicado e pode ser usada com ferramentas de captura de pacotes para obter dados. Mas você precisa determinar os cabeçalhos e os parâmetros de solicitação correspondentes, caso contrário, os dados não podem ser obtidos; muito rastreamento de aplicativo, rastreamento de imagem e vídeo, rastreamento e parada, relativamente leve e flexível, e alta simultaneidade e implantação distribuída também são muito flexíveis , e as funções podem ser mais uma boa realização.

    2) Scrapy framework: pode-se dizer que o scrapy framework é o mais comumente usado e o melhor framework de crawler para crawlers. Ele tem muitas vantagens: scrapy é assíncrono; usa xpath mais legível em vez de regular; estatísticas e sistema de registro poderosos; em ao mesmo tempo Rastreie em URLs diferentes; suporta o modo shell para facilitar a depuração independente; suporta a gravação de middleware para facilitar a gravação de alguns filtros unificados; pode ser armazenado no banco de dados por meio de um pipeline e assim por diante. Essa também é a estrutura a ser introduzida neste artigo (combinada com a biblioteca de selênio).

 

Cinco, realização do projeto

1. A primeira etapa: determinar o tipo de site

    Em primeiro lugar, explique o que significa e que site deve ser visto. Em primeiro lugar, você precisa ver o método de carregamento do site, se é o carregamento estático, carregamento dinâmico (carregamento js) ou outros métodos; diferentes métodos de carregamento requerem diferentes maneiras de lidar com isso. Então observamos o site rastreado hoje e descobrimos que se trata de um fórum cronológico, primeiro adivinhei que era um site carregado estaticamente, abrimos o plugin para organizar o carregamento do js, ​​conforme mostrado na figura abaixo.

Imagem

    Após a atualização, verifica-se que é realmente um site estático (se pode ser carregado normalmente, é basicamente carregado estaticamente).

 

2. Etapa 2: determinar a hierarquia

    Em segundo lugar, o site que queremos rastrear hoje é o site do fórum alimentar, que é um site carregado estaticamente. Já o entendemos durante a análise anterior, e depois a estrutura hierárquica:

 

Imagem

    Provavelmente no processo acima, há um total de três níveis de acesso progressivo, e depois chega-se à página do correio, conforme mostra a figura abaixo.

Imagem

Muitas pessoas aprendem python e não sabem por onde começar.
Muitas pessoas aprendem python e depois de dominar a gramática básica, não sabem onde encontrar casos para começar.
Muitas pessoas que fizeram estudos de caso não sabem como aprender conhecimentos mais avançados.
Portanto, para esses três tipos de pessoas, irei fornecer a vocês uma boa plataforma de aprendizado, gratuita para receber tutoriais em vídeo, e-books e o código-fonte do curso!
Grupo QQ: 721195303

Parte da exibição do código:

    Interface de primeiro nível:

def parse(self, response):
    self.logger.info("已进入网页!")
    self.logger.info("正在获取版块列表!")
    column_path_list = response.css('#ct > div.mn > div:nth-child(2) > div')[:-1]
    for column_path in column_path_list:
        col_paths = column_path.css('div > table > tbody > tr > td > div > a').xpath('@href').extract()
        for path in col_paths:
            block_url = response.urljoin(path)
            yield scrapy.Request(
                url=block_url,
                callback=self.get_next_path,
            )

    Interface secundária:

def get_next_path(self, response):
    self.logger.info("已进入版块!")
    self.logger.info("正在获取文章列表!")
    if response.url == 'http://www.foodmate.net/know/':
        pass
    else:
        try:
            nums = response.css('#fd_page_bottom > div > label > span::text').extract_first().split(' ')[-2]
        except:
            nums = 1
        for num in range(1, int(nums) + 1):
            tbody_list = response.css('#threadlisttableid > tbody')
            for tbody in tbody_list:
                if 'normalthread' in str(tbody):
                    item = LunTanItem()
                    item['article_url'] = response.urljoin(
                        tbody.css('* > tr > th > a.s.xst').xpath('@href').extract_first())
                    item['type'] = response.css(
                        '#ct > div > div.bm.bml.pbn > div.bm_h.cl > h1 > a::text').extract_first()
                    item['title'] = tbody.css('* > tr > th > a.s.xst::text').extract_first()
                    item['spider_type'] = "论坛"
                    item['source'] = "食品论坛"
                    if item['article_url'] != 'http://bbs.foodmate.net/':
                        yield scrapy.Request(
                            url=item['article_url'],
                            callback=self.get_data,
                            meta={'item': item, 'content_info': []}
                        )
        try:
            callback_url = response.css('#fd_page_bottom > div > a.nxt').xpath('@href').extract_first()
            callback_url = response.urljoin(callback_url)
            yield scrapy.Request(
                url=callback_url,
                callback=self.get_next_path,
            )
        except IndexError:
            pass

    Interface de três níveis:

def get_data(self, response):
    self.logger.info("正在爬取论坛数据!")
    item = response.meta['item']
    content_list = []
    divs = response.xpath('//*[@id="postlist"]/div')
    user_name = response.css('div > div.pi > div:nth-child(1) > a::text').extract()
    publish_time = response.css('div.authi > em::text').extract()
    floor = divs.css('* strong> a> em::text').extract()
    s_id = divs.xpath('@id').extract()
    for i in range(len(divs) - 1):
        content = ''
        try:

            strong = response.css('#postmessage_' + s_id[i].split('_')[-1] + '').xpath('string(.)').extract()
            for s in strong:
                content += s.split(';')[-1].lstrip('\r\n')
            datas = dict(content=content,  # 内容
                         reply_id=0,  # 回复的楼层,默认0
                         user_name=user_name[i],  # ⽤户名
                         publish_time=publish_time[i].split('于 ')[-1],  # %Y-%m-%d %H:%M:%S'
                         id='#' + floor[i],  # 楼层
                         )
            content_list.append(datas)
        except IndexError:
            pass
    item['content_info'] = response.meta['content_info']
    item['scrawl_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    item['content_info'] += content_list

    data_url = response.css('#ct > div.pgbtn > a').xpath('@href').extract_first()
    if data_url != None:
        data_url = response.urljoin(data_url)
        yield scrapy.Request(
            url=data_url,
            callback=self.get_data,
            meta={'item': item, 'content_info': item['content_info']}
        )
    else:
        item['scrawl_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.logger.info("正在存储!")
        print('储存成功')
        yield item

 

3. Etapa 3: determinar o método de rastreamento

    Por ser uma página estática, decidi primeiro usar o scrapy framework para obter dados diretamente e, por meio do teste preliminar, descobri que o método era de fato viável. No entanto, naquela época, eu era jovem, frívolo e subestimado as medidas de proteção do site. Devido à paciência limitada, nenhum cronômetro foi adicionado para limitar o rastreamento. A velocidade fez com que eu fosse restringido pelo site, e o site mudou de uma página carregada estaticamente para um algoritmo de verificação de página de carregamento dinâmico antes de entrar no página da web, o acesso direto será rejeitado pelo plano de fundo.

    Mas como esse tipo de problema pode ser minha inteligência? Após um breve período de reflexão (1 dia), mudei o esquema para o método de scrapy framework + biblioteca de selênio e chamei o chromedriver para simular a visita ao site. Depois que o site foi carregado, não seria rastreado. É isso. O acompanhamento comprova que esse método é realmente viável e eficiente.

    A parte de implementação do código é a seguinte:

def process_request(self, request, spider):
    chrome_options = Options()
    chrome_options.add_argument('--headless')  # 使用无头谷歌浏览器模式
    chrome_options.add_argument('--disable-gpu')
    chrome_options.add_argument('--no-sandbox')
    # 指定谷歌浏览器路径
    self.driver = webdriver.Chrome(chrome_options=chrome_options,
                                   executable_path='E:/pycharm/workspace/爬虫/scrapy/chromedriver')
    if request.url != 'http://bbs.foodmate.net/':
        self.driver.get(request.url)
        html = self.driver.page_source
        time.sleep(1)
        self.driver.quit()
        return scrapy.http.HtmlResponse(url=request.url, body=html.encode('utf-8'), encoding='utf-8',
                                        request=request)

 

4. Etapa 4: determinar o formato de armazenamento dos dados rastreados

    Desnecessário dizer que esta parte, de acordo com suas próprias necessidades, defina o formato de dados que precisa ser rastreado em items.py. Basta usar este formato para salvar no projeto:

class LunTanItem(scrapy.Item):
    """
        论坛字段
    """
    title = Field()  # str: 字符类型 | 论坛标题
    content_info = Field()  # str: list类型 | 类型list: [LunTanContentInfoItem1, LunTanContentInfoItem2]
    article_url = Field()  # str: url | 文章链接
    scrawl_time = Field()  # str: 时间格式 参照如下格式 2019-08-01 10:20:00 | 数据爬取时间
    source = Field()  # str: 字符类型 | 论坛名称 eg: 未名BBS, 水木社区, 天涯论坛
    type = Field()  # str: 字符类型 | 板块类型 eg: '财经', '体育', '社会'
    spider_type = Field()  # str: forum | 只能写 'forum'

 

5. Etapa 5: confirme para salvar o banco de dados

    O banco de dados escolhido para este projeto é o mongodb. Por ser um banco de dados não relacional, as vantagens são óbvias e os requisitos de formato não são tão altos e os dados multidimensionais podem ser armazenados de forma flexível. Geralmente é o banco de dados preferido para rastreadores (não me diga redis, vou usá-lo se souber, principalmente não)

    Código:

import pymongo

class FMPipeline():
    def __init__(self):
        super(FMPipeline, self).__init__()
        # client = pymongo.MongoClient('139.217.92.75')
        client = pymongo.MongoClient('localhost')
        db = client.scrapy_FM
        self.collection = db.FM

    def process_item(self, item, spider):
        query = {
            'article_url': item['article_url']
        }
        self.collection.update_one(query, {"$set": dict(item)}, upsert=True)
        return item

    Nesse momento, alguns amigos inteligentes perguntarão: E se os mesmos dados forem rastreados duas vezes? (Em outras palavras, é a função de verificação duplicada)

    Não pensei sobre essa questão antes. Mais tarde, descobri quando perguntei aos grandões. Isso foi feito quando salvamos os dados, apenas esta frase:

query = {
    'article_url': item['article_url']
}
self.collection.update_one(query, {"$set": dict(item)}, upsert=True)

    Determine se há dados duplicados rastejando pelo link da postagem. Se forem duplicados, pode-se entender como cobrindo-os, para que os dados também possam ser atualizados.

 

6. Outras configurações

    Problemas como multi-threading, cabeçalhos, sequência de transmissão de pipeline, etc., estão todos definidos no arquivo settings.py. Para obter detalhes, consulte o projeto do editor para ver. Não vou entrar em detalhes aqui.

 

Sete, tela de efeito

    1. Clique em Executar e o resultado será exibido no console, conforme mostrado na figura abaixo.

Imagem

Imagem

    2. No meio, haverá tarefas de rastreamento que acumulam muitos posts na fila, e então o processamento multi-threaded. Eu configurei 16 threads, e a velocidade ainda é muito impressionante.

Imagem

    3. Exibição de dados do banco de dados:

Imagem

    O content_info armazena todos os comentários de cada postagem e as informações públicas dos usuários relacionados.

 

8. Resumo

    1. Este artigo apresenta principalmente o processo de coleta e armazenamento de dados de sites de alimentos e explica em detalhes como analisar a estrutura da página da web, estratégias de rastreamento, tipos de site, relações hierárquicas, métodos de rastreamento e processos de armazenamento de dados e, finalmente, realizar cada comentário sobre o postar o rastreamento no banco de dados e poder atualizar os dados para evitar rastreamento repetido, anti-rastreamento, etc., os produtos secos estão cheios.

    2. De um modo geral, este projeto não é particularmente difícil. Desde que a ideia esteja certa e as regras de dados sejam encontradas, pode-se dizer que é fácil de levantar. A dificuldade é que o processo não foi concluído antes, e com esta introdução relativamente à água, espero poder ajudá-lo, será minha maior honra.

    3. Ao encontrar problemas, a primeira coisa a pensar não é perguntar a colegas, amigos, professores, mas ir ao Google e ao Baidu para ver se existem situações semelhantes e ver as experiências de outras pessoas. Você deve aprender a descobrir, pensar e resolver os problemas sozinho. Depois disso, o trabalho é muito útil (já me disseram que não saí dos meus tempos de escola, ou seja, gosto de perguntar aos meus colegas). Depois de verificar certas informações online, continuo não tenho ideia, e depois pergunte aos outros, outros estarão mais dispostos a ajudar o seu ~

 

Ainda quero recomendar o grupo de aprendizagem Python que criei por mim mesmo : 721195303 , todos os quais estão aprendendo Python. Se você quiser aprender ou estiver aprendendo Python, seja bem-vindo. Todos são parte do desenvolvimento de software e compartilham produtos secos de de vez em quando (apenas relacionado ao desenvolvimento de software Python), incluindo uma cópia dos materiais avançados mais recentes do Python e ensino baseado em zero compilado por mim em 2021. Bem-vindos amigos que estão em nível avançado e interessados ​​em Python!

Acho que você gosta

Origin blog.csdn.net/pyjishu/article/details/114652698
Recomendado
Clasificación