• 基于scrapy框架输入关键字爬取有关贴吧帖子


    基于scrapy框架输入关键字爬取有关贴吧帖子

    站点分析

    首先进入一个贴吧,要想达到输入关键词爬取爬取指定贴吧,必然需要利用搜索引擎
    进入贴吧
    点进看到有四种搜索方式,分别试一次,观察url变化
    搜索页面
    我们得知:
    搜索贴吧:http://tieba.baidu.com/f/search/fm?ie=UTF-8&qw=dfd
    搜索帖子:http://tieba.baidu.com/f/search/res?ie=utf-8&qw=dfd
    其中参数qw是搜索关键词,由此我们可以构建搜索贴吧的url
    获取贴吧
    搜索得到的页面,可以得到我们需要的贴吧url
    贴吧
    我们就可以轻而易举的得到我们搜索的相关贴吧

    下面对贴吧主页进行分析
    进入贴吧F12查看

    显然我们知道#thread_list这个列表,观察看到这就是每个贴在,注意li标签里的data-field字段有我们需要的信息, 不过我们只需要得到帖子的url,之后对帖子进一步提取,其中data-tid就是贴子的id,通过这个我们可以定位唯一的帖子
    如data-tid="6410699527", 则帖子的url为teiba.baidu.com/p/6410699527具体的探索过程就不一一阐述了。。。

    对帖子分析
    在这里插入图片描述
    在这里插入图片描述
    直接源码省去很多字、、、的寻找过程,我们在源码找到了一段JavaScript代码,其中firstpost就是楼主发的帖子。。为什么不在HTML便签中提取?因为你试试就知道了,开始我就是在HTML便签中提取的,部分贴吧标题提取不出来。firstpost有着很详细的信息,标题,内容,时间
    现在对贴吧的回复贴吧提取:
    在这里插入图片描述
    探索得知,很多带有表情的回复帖,内容很乱,打算正则提取。。。
    一个小白的分析过程想的多,看的慢,难受!这里就不在阐述了,不然分析过程写不下

    items.py编写

    在这个模块里定义自己的字段,这里我们需要帖子的标题,内容,作者,时间,回复数,回复内容
    源码:
    # -*- coding: utf-8 -*-
    import scrapy
    
    class postDataItem(scrapy.Item):
        tid = scrapy.Field()
        title = scrapy.Field()
        content = scrapy.Field()
        author_name = scrapy.Field()
        date = scrapy.Field()
        reply_content = scrapy.Field()
        reply_num = scrapy.Field()
        device = scrapy.Field()#这给字段读者不必关注,项目所需
    

    pipelines.py的编写

    没有;
    哈哈,还没想好用什么数据库
    

    爬虫模块的编写

    # -*- coding: utf-8 -*-
    import scrapy
    from urllib.parse import urlencode
    from scrapy.http import Request
    import re
    import time
    from ..items import postDataItem
    class BtspiderSpider(scrapy.Spider):
        name = 'btSpider'
        allowed_domains = ['tieba.baidu.com']
        base_url = 'http://tieba.baidu.com'
    
        def start_requests(self):
            """
            开始搜索相关学校贴吧
            """
            search_base_url = 'http://tieba.baidu.com/f/search/fm?ie=UTF-8&'
            arg1 = urlencode({'qw':self.school}) #通过命令行传递属性
            search_url = search_base_url + arg1
            yield Request(url=search_url, callback=self.get_search_page_urls, dont_filter=True) #搜索的url送到调度器, 注意:这个url不参与去重下面用到
    
        def get_search_page_urls(self, response):
            """
            获得搜索结果所有页面,
            发送每页的url到调度器
            """
            pager_search = response.xpath("//div[@class='pager pager-search']/a/@href").extract()[:-2]
            pager_search = [(self.base_url + pager) for pager in pager_search ]
            pager_search.append(response.url)
            for pager_url in pager_search:
                yield Request(url=pager_url, callback=self.get_forum_urls)
    
        def get_forum_urls(self, response):
            """
            获得所有相关贴吧的url送到调度器
            """
            forum_lists = response.xpath('//div[@class="search-forum-list"]/div[@class="forum-item clear-float"]')
            for forum in forum_lists:
               forum_url = self.base_url + forum.xpath('./div[@class="left"]/a/@href').extract_first()
               yield Request(url=forum_url, callback=self.get_post_urls)
    
        def get_post_urls(self, response):
            """
            获得所有帖子的url
            """
            postList = response.xpath("//li[@class=' j_thread_list clearfix']")
            for post in postList:
                data_tid = post.xpath("./@data-tid").extract_first()
                post_url = self.base_url + '/p/' + data_tid
                yield Request(url=post_url, callback=self.get_post_data)
            #实现翻页操作
            url_list = response.xpath("//div[@id='frs_list_pager']/a")[:-2]
            for url in url_list:
                if int(re.findall('.*pn=(d*)', url.xpath('./@href').extract_first())[0]) <= 20000:
                    yield response.follow(url=url, callback=self.get_post_urls)
                else:
                    break
    
    
    
        def get_post_data(self, response):
            post_data_item = postDataItem()
            # 提取帖子id
            tid = re.compile("https?://tieba.baidu.com/p/(d*).*").findall(response.url)[0]
            post_data_item['tid'] = tid
    
            # 提取帖子内容的正则表达式,来源为页面底部JavaScript代码
            rpost = '"firstPost": {"title":"(?P<title>.*)","content":"(?P<content>.*)","is_vote".*"now_time":(?P<date>d*)'
            post = re.search(rpost, response.text)
            # 将字符串Unicode编码转换为中文
            dirty_title = post.group('title').encode('utf-8').decode("unicode_escape")
            dirty_content = post.group('content').encode('utf-8').decode("unicode_escape")
            # 找到所有标签替换为空
            post_data_item['title'] = re.sub('<.*?>', '', dirty_title)
            post_data_item['content'] = re.sub('<.*?>', '', dirty_content)
            # 时间戳转换为字符串时间
            post_data_item['date'] = time.strftime("%Y-%m-%d %X", time.localtime(int(post.group('date'))))
    
            # 提取作者的xpath表达式
            xauthor = "//div[contains(@class, 'louzhubiaoshi')]/@author"
            post_data_item['author_name'] = response.xpath(xauthor).extract_first()
    
            # 提取楼层回复内容的xpath表达式,是所有的内容
            # 这是经过清洗的数据用它来做分析
            xreply_content = "//div[contains(@class, 'd_post_content')]/text()"
            all_content = response.xpath(xreply_content).extract()
            all_content_dirty = ''.join(all_content)
            post_data_item['reply_content'] = ''.join(re.findall(r'[u4e00-u9fa5]', all_content_dirty))
    
            # 提取帖子回复数量的xpath表达式
            xreply_num = "//span[@class='red']/text()"
            post_data_item['reply_num'] = response.xpath(xreply_num).extract_first()
    
            for key, value in post_data_item.items():
                print(key, value)
    

    运行结果

    在这里插入图片描述
    注意这是,我爬虫的精简版,只专注于一个帖子爬取

  • 相关阅读:
    第五次实验作业
    第四次作业
    java三
    java作业二
    java作业一
    作业11
    作业10
    作业9
    作业8
    作业7
  • 原文地址:https://www.cnblogs.com/xunjishu/p/12723455.html
Copyright © 2020-2023  润新知