Python Scrap框架教学,爬取某食品论坛数据

Python Scrap框架教学,爬取某食品论坛数据,第1张

概述本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。以下文章来源于Python爬虫与数据挖掘,作者杯酒先生一、前言网络爬虫(又称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

以下文章来源于Python爬虫与数据挖掘 ,作者 杯酒先生

一、前言

网络爬虫(又称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。------百度百科

说人话就是,爬虫是用来海量规则化获取数据,然后进行处理和运用,在大数据、金融、机器学习等等方面都是必须的支撑条件之一。

目前在一线城市中,爬虫的岗位薪资待遇都是比较客观的,之后提升到中、高级爬虫工程师,数据分析师、大数据开发岗位等,都是很好的过渡。

Python爬虫、数据分析、网站开发等案例教程视频免费在线观看

https://space.bilibili.com/523606542 
Python学习交流群:1039649593二、项目目标

本次介绍的项目其实不用想得太过复杂,最终要实现的目标也就是将帖子的每条评论爬取到数据库中,并且做到可以更新数据,防止重复爬取,反爬等措施。

 

三、项目准备

这部分主要是介绍本文需要用到的工具,涉及的库,网页等信息等

软件:PyCharm

需要的库:Scrapy, selenium, pymongo, user_agent,datetime

目标网站:

http://bbs.foodmate.net

插件:Chromedriver(版本要对)

 

四、项目分析

1、确定爬取网站的结构

简而言之:确定网站的加载方式,怎样才能正确的一级一级的进入到帖子中抓取数据,使用什么格式保存数据等。

其次,观察网站的层级结构,也就是说,怎么根据板块,一点点进入到帖子页面中,这对本次爬虫任务非常重要,也是主要编写代码的部分。

 

2、如何选择合适的方式爬取数据?

目前我知道的爬虫方法大概有如下(不全,但是比较常用):

1)request框架:运用这个http库可以很灵活的爬取需要的数据,简单但是过程稍微繁琐,并且可以配合抓包工具对数据进行获取。但是需要确定headers头以及相应的请求参数,否则无法获取数据;很多app爬取、图片视频爬取随爬随停,比较轻量灵活,并且高并发与分布式部署也非常灵活,对于功能可以更好实现。

2)scrapy框架:scrapy框架可以说是爬虫最常用,最好用的爬虫框架了,优点很多:scrapy 是异步的;采取可读性更强的 xpath 代替正则;强大的统计和 log 系统;同时在不同的 url 上爬行;支持 shell 方式,方便独立调试;支持写 mIDdleware方便写一些统一的过滤器;可以通过管道的方式存入数据库等等。这也是本次文章所要介绍的框架(结合selenium库)。

 

五、项目实现

1、第一步:确定网站类型

首先解释一下是什么意思,看什么网站,首先要看网站的加载方式,是静态加载,还是动态加载(Js加载),还是别的方式;根据不一样的加载方式需要不同的办法应对。然后我们观察今天爬取的网站,发现这是一个有年代感的论坛,首先猜测是静态加载的网站;我们开启组织 Js 加载的插件,如下图所示。

 

刷新之后发现确实是静态网站(如果可以正常加载基本都是静态加载的)。

 

2、第二步:确定层级关系

其次,我们今天要爬取的网站是食品论坛网站,是静态加载的网站,在之前分析的时候已经了解了,然后是层级结构:

 

大概是上面的流程,总共有三级递进访问,之后到达帖子页面,如下图所示。

 

部分代码展示:

一级界面:

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,           

二级界面:

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

三级界面:

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、第三步:确定爬取方法

由于是静态网页,首先决定采用的是scrapy框架直接获取数据,并且通过前期测试发现方法确实可行,不过当时年少轻狂,小看了网站的保护措施,由于耐心有限,没有加上定时器限制爬取速度,导致我被网站加了限制,并且网站由静态加载网页变为:动态加载网页验证算法之后再进入到该网页,直接访问会被后台拒绝。

但是这种问题怎么会难道我这小聪明,经过我短暂地思考(1天),我将方案改为scrapy框架 + selenium库的方法,通过调用Chromedriver,模拟访问网站,等网站加载完了再爬取不就完了,后续证明这个方法确实可行,并且效率也不错。

实现部分代码如下:

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、第四步:确定爬取数据的储存格式

这部分不用多说,根据自己需求,将需要爬取的数据格式设置在items.py中。在工程中引用该格式保存即可:

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、第五步:确定保存数据库

本次项目选择保存的数据库为mongodb,由于是非关系型数据库,优点显而易见,对格式要求没有那么高,可以灵活储存多维数据,一般是爬虫优选数据库(不要和我说redis,会了我也用,主要是不会)

代码:

import pymongoclass 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)m

这时,有聪明的盆友就会问:如果运行两次爬取到了一样的数据怎么办呢?(换句话说就是查重功能)

这个问题之前我也没有考虑,后来在我询问大佬的过程中知道了,在我们存数据的时候就已经做完这件事了,就是这句:

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

通过帖子的链接确定是否有数据爬取重复,如果重复可以理解为将其覆盖,这样也可以做到更新数据。

 

6、其他设置

像多线程、headers头,管道传输顺序等问题,都在settings.py文件中设置,具体可以参考小编的项目去看,这里不再赘述。

 

七、效果展示

1、点击运行,结果显示在控制台,如下图所示。

 

 

2、中间会一直向队列中堆很多帖子的爬取任务,然后多线程处理,我设置的是16线程,速度还是很可观的。

 

3、数据库数据展示:

 

content_info中存放着每个帖子的全部留言以及相关用户的公开信息。

总结

以上是内存溢出为你收集整理的Python Scrap框架教学,爬取某食品论坛数据全部内容,希望文章能够帮你解决Python Scrap框架教学,爬取某食品论坛数据所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1188703.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存