精华内容
下载资源
问答
  • 嵩天老师的课程:Python数据分析与展示 + Python网络爬虫与信息提取 包含课程视屏,课件 送哈工大mooc python教程
  • 基于Python的网络爬虫与数据可视化分析

    万次阅读 多人点赞 2020-07-26 10:43:12
    网络爬虫是一个专门从万维网上下载网页并分析网页的程序。它将下载的网页和采集到的网页信息存储在本地数据库中以供搜索引擎使用。网络爬虫的工作原理是从一个或若干初始网页的链接开始进而得到一个链接

    1 背景分析

    在互联网技术迅速发展的背景下,网络数据呈现出爆炸式增长,对数据的应用需要在大量数据中记性挖掘搜索,搜索引擎结合这一需求就应运而生,不只是搜索数据信息,还要帮助人们找到需要的结果被人们所应用。信息数据的处理就需要爬虫技术加以应用来收集网络信息。作为搜索引擎的重要组成部分,网络爬虫的设计直接影响着搜索引擎的质量。网络爬虫是一个专门从万维网上下载网页并分析网页的程序。它将下载的网页和采集到的网页信息存储在本地数据库中以供搜索引擎使用。网络爬虫的工作原理是从一个或若干初始网页的链接开始进而得到一个链接队列。伴随着网页的抓取又不断从抓取到的网页里抽取新的链接放入到链接队列中,直到爬虫程序满足系统的某一条件时停止。
    Python语言简单易用,现成的爬虫框架和工具包降低了使用门槛,具体使用时配合正则表达式的运用,使得数据抓取工作变得生动有趣。在数据搜索方面,现在的搜索引擎虽然比刚开始有了很大的进步,但对于一些特殊数据搜索或复杂搜索,还不能很好的完成,利用搜索引擎的数据不能满足需求,网络安全,产品调研,都需要数据支持,而网络上没有现成的数据,需要自己手动去搜索、分析、提炼,格式化为满足需求的数据,而利用网络爬虫能自动完成数据获取,汇总的工作,大大提升了工作效率。
    网络在我们的生活中越来越重要,网络的信息量也越来越大,研究该课题可以更好的理解网络爬虫的原理以及可视化分析的作用。

    2 需求分析

    现在的社会已经进入了信息时代,尤其是网络购物成为一种很普遍的购物方式,大数据的获取和分析对于促进经济发展有着重要的意义。掌握消费者的爱好和习惯,有助于商家及时的调整商品的类型和定价。
    手机在我们的日常生活中使用的越来越频繁,为了更好的掌握消费者对于手机品牌、价格以及店铺的喜好程度,我们选取京东网站的手机产品作为我们研究的目标,通过网络爬虫技术获取网站的数据,利用数据库技术存储数据,最后用可视化分析的形式给出我们最终的研究结果。

    3 详细设计及技术原理

    项目设计主要分为几个步骤:根据需求,确定我们需要爬取的网站和数据类型;通过Python爬虫技术对网页进行解析;将数据持久化,存储到数据库中,以便于随时提取、查询、添加数据;通过获取的数据进行可视化分析,得到我们的结论。整个过程如图3.1所示:
    在这里插入图片描述

    图3.1 项目设计流程图

    3.1 网络爬虫技术简介

    网络爬虫技术,别名“网络蜘蛛”,指的就是一种通过依照既定程序自动获取网页信息或脚本的技术。其可以在互联网当中帮助搜索引擎下载各类信息资料,并通过依次进行数据的采集和分析处理。最后完成数据的统一存储。当程序处于正常运行阶段时,爬虫会从一个或多个初始URL开始下载网页内容,随后依托搜索方式或内容匹配法将网页中其所需内容进行精准“抓取”,与此同时爬虫也会不间断地从网页中获取新URL。当爬虫检索到的信息满足停止条件时将自动停止检索。此时其将自动进入到抓取数据的处理环节,通过构建索引并妥善存储数据,使得用户可以依照自身的实际需求随时提取、查阅数据库中的数据资料。
    基于Python的网络爬虫技术,因使用了Python编写程序,可以抛弃传统笨重的IDE,仅使用一个文本编辑器便可以基本完成开发网络爬虫技术功能,为技术人员的编程工作提供巨大便利。加之Python本身拥有相对比较完善的爬虫框架,可支持迅速挖掘、提取和处理信息数据等程序任务。在充分发挥Python强大网络能力下,即便面对海量的信息数据检索要求,只通过编写少数代码便可以有效完成网页下载并利用其网页解析库,准确解读和表达各网页标签,以有效提升抓取数据的质量水平。

    4 功能实现

    本项目以手机为例,对京东商城中50多个手机品牌(华为、Apple、小米、OPPO、VIVO……)进行了数据的爬取,获得了超过5万条的数据,包括商品品牌、商品名称、售价、店铺信息、评价量等信息,并将数据存储到MySQL数据库中。在数据分析阶段,我们对获取到的数据从多个角度进行了可视化分析,并给出了我们的结论。

    4.1 网页分析

    4.1.1 URL地址构建

    登录京东网站,搜索关键词“手机”可以发现,在返回的搜索结果中,虽然显示有83万+件商品,但页面只有100页,每页只有60件商品。这是由于京东网站的反爬虫机制,导致无法显示所有的商品。为了获得更多的数据量,我们采用二级关键词进行检索的方式,在图4.1中我们可以看到,在品牌那一栏有所有的手机品牌信息,如“华为手机”、“Apple手机”,这样可以在很大程度上增加我们的数据量。
    在这里插入图片描述

    图4.1 京东网站商品列表页面

    构建URL地址。查看搜索二级关键词之后的网站地址:https://search.jd.com/search?keyword=%E6%89%8B%E6%9C%BA&wq=%E6%89%8B%E6%9C%BA&ev=exbrand_%E5%8D%8E%E4%B8%BA%EF%BC%88HUAWEI%EF%BC%89%5E。此时的网址看上去比较复杂,图中的汉字已经进行过重新编码,我们还需要对其简化处理,简化后构建的URL为:
    https://search.jd.com/Search?’ + parse.urlencode(keyword) + ‘&ev=exbrand_%s’%(华为) + ‘&enc=utf-8’ + ‘&page=%s’%(2n-1)
    使用urlencode将keyword转码成可识别的url格式,enc以utf-8方式编码,并得传入对应page,得到完整的url。Keyword处代表关键词“手机”, exbrand后面代表的是二级关键词,如“华为(HUAWEI)”。另外京东网站的page变化规律是n
    2-1。这样就构建出我们的URL地址。

    4.1.2 网页分析

    通过分析网页的元素,可以找到商品列表在good-list中,继续往下分析可以找到商品名称、手机价格、评价量、店铺信息、图片地址、商品地址等数据。首先导入bs4包,然后就可以使用BeautifulSoup库了,通过使用BeautifulSoup提供的强大的解析方法,即可解析出网页中我们想要的数据。
    在这里插入图片描述

    图4.2 网页审查元素页面

    4.2 数据库存储

    MySQL是一种关系型数据库,关系型数据库最重要的概念就是表,表具有固定的列数和任意的行数,在数学上称为“关系”二维表是同类实体的各种属性的集合,每个实体对应于表中的一行,在关系中称为元组,相当于通常的一条记录,表中的列属性,称为Field,相当于通常记录中的一个数据项,也叫做列、字段。
    首先,打开数据库连接之前,一定保证打开MySQL服务,否则就会出现连接失败的情况。Navicat for MySQL是一款强大的MySQL数据库管理和开发工具,它为专业开发者提供了一套强大的足够尖端的工具,对于数据库的可视化是很方便简洁的。然后,我们要设置好数据库连接的相关配置,以便于我们可以在Python中成功连接数据库,包括数地址、端口号、用户名、密码,具体的配置信息如图4.3所示:
    在这里插入图片描述

    图4.3 数据库连接配置信息

    最后,在数据库中创建表格,用来存储数据。数据库建表语句如图4.4所示。我们建立的商品信息表包含8列,分别是商品ID、手机品牌、商品名称、价格、店铺信息、评论量、图片地址、商品详情页地址。并且以京东的商品ID为主键,这样做可以避免因为商品名称的重复导致的保存失败的情况,每一件商品的ID在京东商城里都是唯一的。
    在这里插入图片描述

    图4.4 数据库建表语句

    4.3 爬取数据过程

    在完成上述工作及配置之后,我们就可以正式的编写代码来爬取数据了。将我们的爬虫伪装成浏览器去获取网页,然后对网页解析,得到我们需要的数据,最后将数据存储到MySQL数据库中。为了保证报告的美观和质量,在此部分将不再展示代码,全部的源代码见附录。最终得到的数据如图4.5所示:
    在这里插入图片描述

    图4.5 MySQL数据库中的数据

    5 数据分析

    在得到数据之后,我们对数据进行了全方面多维度的分析,在原有数据的技术上进行深度挖掘,具体的过程如下。

    5.1 数据的预处理

    从图5.1中可以看出,由于我们直接得到的数据里面的数据类型以及可用的信息比较少,品牌名称比较混乱复杂,商品名称较长无法知道商品具体属性,评论数量单位不统一等,这些问题的存在会直接影响我们的分析结果。
    在这里插入图片描述

    图5.1 原始数据图

    为了更方便我们的处理,在可视化分析之前,我们对数据进行了预处理操作,如图5.2所示。首先对于手机品牌,删除无用的后缀括号里的内容,使名称看上去更加简洁。其次对评论量进行了处理,将带单位“万”的数据都进行了单位的统一,方便我们后续计算使用。然后我们利用关键词检索的方式,对商品类型进行了划分,判断出它们是属于手机还是配件,是新手机还是二手手机,这些对于后续的统计计算结果有着非常大的影响。最后,我们对手机类型进行了划分,分为智能手机、商务手机、老年手机、5G手机、学生手机,在后续的处理中,我们会对不同类型的手机价格及购买人数进行可视化分析。
    在这里插入图片描述

    图5.2 预处理之后的数据

    我们主要从三个大角度对数据进行可视化分析:店铺销量分析、品牌商品分析、手机类型分析。由于京东网站上不显示具体的销量,这里我们把评论量近似等于购买人数,后面不再进行说明。

    5.2 店铺销量分析

    5.2.1 不同店铺销量分析

    我们选取了销量前7的店铺进行了对比分析,从图5.3中可以看出,“荣耀京东自营店”、“小米京东自营旗舰店”、“华为京东自营官方旗舰店”、“Apple产品京东自营旗舰店”的销量占比比重较大,也反映出华为、小米、Apple的手机产品在市场中占有比较大的份额。
    在这里插入图片描述

    图5.3 不同店铺销量分析

    5.2.2 不同店铺平均售价分析

    在这里插入图片描述

    图5.4 售价8000元以上店铺平均售价分析

    由于品牌众多,考虑到报告篇幅的限制,无法将所有的店铺均价一一对比显示,我们选取平均售价8000元以上的店铺进行对比分析。从图5.4中可以看出,“VERTU官方旗舰店”的手机均价最高,达到了近8万元,其他比较高端的手机品牌店铺售价也都在一万元左右。

    5.3 品牌商品分析

    5.3.1 不同价格区间购买人数

    为了更好的看到不同的价格区间的购买人数信息,我们对原始数据进行了价格分层,500元以下、500-1000元、1000-3000元、3000-5000元、5000元以上。从图5.5中可以看出,大部分人的选择在1000-3000元之间,占比39.55%。只有7.33%的人选择购买5000元以上的手机。
    在这里插入图片描述

    图5.5 不同价格区间购买人数

    5.3.2 不同品牌的平均价格

    在图5.6中,我们以柱状图的形式将不同品牌的平均价格展示出来,从中可以看出,均价3000元以上的手机品牌中,Vertu品牌的均价最高,达到近6万元,其他品牌均价在1万元左右;均价1000-3000元的手机品牌的差距不是特别明显,黑鲨、华为、OPPO、iQOO、一加这几个品牌的手机均价较高。

    在这里插入图片描述
    在这里插入图片描述

    图5.6 不同品牌的平均价格

    5.3.3 商品价格与购买人数关系

    在有大量的数据下,散点图相比于其他的图形,在反映两个变量相互关系下更具有优势。为了更直观的看出商品价格与购买人数之间的关系,我们采用散点图的形式,将其表现出来。
    从图5.7中可以看出,排除个别品牌或者店铺影响力的情况下,从总体分布情况来看,商品的售价越低,购买人数越多;商品售价越高,购买人数越少。因此,根据这些可以帮助商家及时的调整价格,增加销量。
    在这里插入图片描述

    图5.7 商品价格与购买人数关系散点图

    5.4 手机类型分析

    5.4.1 不同手机类型平均价格分析

    目前市面上充斥着各种类型的手机商品,特别是近年来,“5G手机”成为大众追捧的热点。因此,我们对不同的手机类型进行了对比分析。如图5.8所示,商务手机相比于其他手机要贵很多,均价达到近1万元;其次是5G手机,随着近年的快速发展,其价格相比于普通的智能手机要高一点,达到了近5000元;另外,老年手机和学生手机因为功能较少,配置较低,因此它的售价也比较低,只有500元左右。
    在这里插入图片描述

    图5.8 不同手机类型平均价格分析

    5.4.2 不同手机类型购买人数占比分析

    从图5.9中可以看出,有80.8%的人选择购买普通智能手机;5G手机的占比还比较少,只有6%;老年手机占比11.8%。
    在这里插入图片描述

    图5.9 不同手机类型购买人数占比分析

    6 结论

    通过几周对Python爬虫以及数据可视化分析的学习,我们在这过程中查阅了大量的资料,经过多次实验分析,最终形成我们的项目报告。主要实现了对京东商城中手机商品数据的爬取以及数据分析工作,掌握了Python常用包函数以及数据库的使用方法。总体而言,网络编程这门课让我们学到了很多的东西,网络在我们身边无处不在,学会网络编程对于我们日常的学习和工作都有很大的帮助。
    由于时间有限,我们的项目还有一定的不足,后续有机会将会继续改进。

    有问题可以随时留言交流

    展开全文
  • Python网络爬虫与信息提取 (实例)股票数据定向爬虫

    功能描述

    目标:获取上交所和深交所所有股票的名称和交易信息

    股票数据是进行量化交易的基础型数据,此爬虫也能为量化交易提供获得基础数据的方法

    输出:保存到文件中

    技术路线:requestsbs4re

    候选数据网站的选择

    新浪股票:http://finance.sina.com.cn/stock/

    百度股票:https://gupiao.baidu.com/stock/

    选取原则:股票信息静态存在于HTML页面中,js代码生成

    没有Robots协议限制

    选取方法:浏览器 F12,源代码查看等

    选取心态:不要纠结于某个网站,多找信息源尝试

    数据网站的确定

    新浪股票在页面上看到的股票代码在源代码中并没有,说明很可能是由JavaScript脚本生成的;而百度股票的每一支个股的信息都写在HTML代码中

    所以对于这两个网站来讲,百度股票更适合作为定向爬虫的数据来源

    获取股票列表:

    东方财富网:http://quote.eastmoney.com/stocklist.html

    获取个股信息:

    百度股票:https://gupiao.baidu.com/stock/

    单个股票:https://gupiao.baidu.com/stock/sz002439.html

    程序的结构设计

    步骤1:从东方财富网获取股票列表

    步骤2:根据股票列表逐个到百度股票获取个股信息

    步骤3:将结果存储到文件

     

    百度股票源代码中个股信息的组织形式

    所以键值对,用字典类型


    实例编写

    为了调试方便,使用traceback

    import requests
    from bs4 import BeautifulSoup
    import traceback
    import re
    
    def getHTMLText(url):
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def getStockList(lst, stockURL):
        html = getHTMLText(stockURL)
        soup = BeautifulSoup(html, 'html.parser') 
        a = soup.find_all('a')
        for i in a:
            try:
                href = i.attrs['href']
                lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
            except:
                continue
    
    def getStockInfo(lst, stockURL, fpath):
        for stock in lst:
            url = stockURL + stock + ".html"
            html = getHTMLText(url)
            try:
                if html=="":
                    continue
                infoDict = {}
                soup = BeautifulSoup(html, 'html.parser')
                stockInfo = soup.find('div',attrs={'class':'stock-bets'})
    
                name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
                infoDict.update({'股票名称': name.text.split()[0]})
                
                keyList = stockInfo.find_all('dt')
                valueList = stockInfo.find_all('dd')
                for i in range(len(keyList)):
                    key = keyList[i].text
                    val = valueList[i].text
                    infoDict[key] = val
                
                with open(fpath, 'a', encoding='utf-8') as f:
                    f.write( str(infoDict) + '\n' )
            except:
                traceback.print_exc()
                continue
    
    def main():
        stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
        stock_info_url = 'https://gupiao.baidu.com/stock/'
        output_file = 'D:/BaiduStockInfo.txt'
        slist=[]
        getStockList(slist, stock_list_url)
        getStockInfo(slist, stock_info_url, output_file)
    
    main()
     


    实例优化

    如何提高用户体验?

    速度提高:编码识别的优化

    r.apparent_encoding需要分析文本,运行较慢,可辅助人工分析

    体验提高:增加动态进度显示

     

    import requests
    from bs4 import BeautifulSoup
    import traceback
    import re
    
    def getHTMLText(url, code="utf-8"):
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = code
            return r.text
        except:
            return ""
    
    def getStockList(lst, stockURL):
        html = getHTMLText(stockURL, "GB2312")
        soup = BeautifulSoup(html, 'html.parser') 
        a = soup.find_all('a')
        for i in a:
            try:
                href = i.attrs['href']
                lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
            except:
                continue
    
    def getStockInfo(lst, stockURL, fpath):
        count = 0
        for stock in lst:
            url = stockURL + stock + ".html"
            html = getHTMLText(url)
            try:
                if html=="":
                    continue
                infoDict = {}
                soup = BeautifulSoup(html, 'html.parser')
                stockInfo = soup.find('div',attrs={'class':'stock-bets'})
    
                name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
                infoDict.update({'股票名称': name.text.split()[0]})
                
                keyList = stockInfo.find_all('dt')
                valueList = stockInfo.find_all('dd')
                for i in range(len(keyList)):
                    key = keyList[i].text
                    val = valueList[i].text
                    infoDict[key] = val
                
                with open(fpath, 'a', encoding='utf-8') as f:
                    f.write( str(infoDict) + '\n' )
                    count = count + 1
                    print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
            except:
                count = count + 1
                print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
                continue
    
    def main():
        stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
        stock_info_url = 'https://gupiao.baidu.com/stock/'
        output_file = 'D:/BaiduStockInfo.txt'
        slist=[]
        getStockList(slist, stock_list_url)
        getStockInfo(slist, stock_info_url, output_file)
    
    main()


    总结

    采用requestsbs4re路线实现了股票信息爬取和存储

    实现了展示爬取进程的动态滚动条

    展开全文
  • python网络爬虫与信息提取

    千次阅读 多人点赞 2018-11-28 11:33:28
    课程《Python网络爬虫与信息提取-北京理工大学-嵩天》中的内容,作为笔记 Table of Contents 一、网络爬虫之规则:Requests库 1. request()方法 2. 其他方法  3. 爬取网页的通用代码框架 4. 实例 5. 网络...

    课程《Python网络爬虫与信息提取-北京理工大学-嵩天》中的内容,作为笔记

    Table of Contents

    一、网络爬虫之规则:Requests库

    1. request()方法

    2. 其他方法 

    3. 爬取网页的通用代码框架

    4. 实例

    5. 网络爬虫的“盗亦有道”

    二、网络爬虫之提取

    1.Beautiful Soup库

    2. 信息组织与提取方法

    3. 实例:中国大学排名定向爬虫

    4、正则表达式入门

    5.实例:当当网比价定向爬虫

    实例:股票数据定向爬虫

    三、Scrapy爬虫框架

    Scrapy爬虫框架介绍

    实例:Scrapy获取上交所和深交所所有股票的名称和交易信息


    一、网络爬虫之规则:Requests库

    爬取网页的最好的第三方库,简单简洁,更多信息可访问http://www.python-requests.org

    安装方法:Anaconda中已经包含了这个库,如果要安装,使用命令:pip install requests

    requests的7个主要方法:

    方法 说明 HTTP协议方法
    requests.request() 构造一个请求,支撑以下各方法的基础方法  
    requests.get() 获取html网页的主要方法,对应于http的get GET
    request.head() 获取html网页头信息的方法,对应于http的head HEAD
    request.post() 向html网页提交post请求的方法,对应于http的post POST
    request.put() 向html网页提交put请求的方法,对应于http的put PUT
    request.patch() 向html网页提交局部修改请求,对应于http的patch PATCH
    request.delete() 向html提交删除请求,对应于http的delete DELETE

    HTTP对资源的操作:

    方法 说明
    GET 请求获取URL位置的资源
    HEAD 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息
    POST 请求向URL位置的资源后附加新的数据
    PUT 请求向URL位置存储一个资源,覆盖原URL位置的资源
    PATCH 请求局部更新URL位置的资源,覆盖原URL位置的资源
    DELETE 请求删除URL位置存储的资源

    1. request()方法

    def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.
    
        :param method: 请求方式,对应GET/HEAD/POST/PUT/PATCH/delete/OPTIONS,OPTIONS获取服务器参数,使用较少.
        :param url: 访问链接.
        :**kwargs: 控制访问的参数,均为可选项
        :param params:  字典或者字节序列,作为参数增加到url中.可以将一些键值对增加到url中,服务器根据参数返回资源.
            kv = {'key1':'value1', 'key2':'value2'}
            r = requests.request('GET', "http://www.python123.io/ws", params=kv)
            print(r.url) #https://www.python123.io/ws?key1=value1&key2=value2
        :param data: 字典,字节序列或文件对象,作为request的内容.
            r = requests.request('POST', "http://www.python123.io/ws", data=kv)
            body = '主体内容'
            r = requests.request('POST', "http://www.python123.io/ws", data=body)
        :param json: json格式的数据,作为request的内容,向服务器提交.
            r = requests.request('POST', "http://www.python123.io/ws", json=kv)
        :param headers: 字典,http定制头,模拟浏览器的访问.
            hd = {'user-agent' : 'Chrome/10'}
            r = requests.request('POST', "http://www.python123.io/ws", headers = hd)
        :param cookies: 字典或CookieJar,Request中的cookie
        :param files: 字典类型,传输文件.
            fs = {'file' : open('data.xls', 'rb')}
            r = requests.request('POST', "http://www.python123.io/ws", files=fs)
        :param auth: 元组,支持http认证功能.
        :param timeout: 设定的超时时间,秒为单位,超时后产生timeout异常
        :param allow_redirects: bool, 重定向开关,默认为True.
        :type allow_redirects: bool
        :param proxies: 字典类型,设定访问代理服务器,可以增加登录认证.
            proxy = {'http': 'http://127.0.0.1:1080',
                     'https': 'https://127.0.0.1:1080'}
            r = requests.request('POST', "http://www.python123.io/ws", proxies = proxy)
        :param verify: bool, 默认为True, 认证SSL证书开关.
        :param stream: bool, 默认为True, 获取内容立即下载开关.
        :param cert: 本地SSL证书路径.
    
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

    函数返回Response对象,Response对象的属性如下:

    属性 说明
    r.status_code http请求的返回状态,200表示连接成功,404表示失败
    t.text http响应内容的字符串形式,即url的页面内容
    r.encoding

    从http header中猜测的响应内容的编码方式 。

    如果header中不存在charset,则认为编码为ISO-8859-1,这个编码不能解析中文

    r.apparent_encoding

    从内容中分析出的响应内容编码方式(备选编码方式)。

    从网页内容中推断编码方式,更加准确一些,当encoding不能解析正确编码方式时,采用这个

    r.content http响应内容的二进制形式

    使用流程:获取response对象->检测状态码->获取内容

    2. 其他方法 

    get()等方法只是对requests()方法做了封装,可以被request()方法替代

    def get(url, params=None, **kwargs):
        """Sends a GET request.
    
        url: 拟获取页面的url链接.
        params: url中的额外参数,字典或字节流格式,可选.
        **kwargs: 12个控制访问的参数.
        """
        return request('get', url, params=params, **kwargs)
    
    def head(url, **kwargs):
        r"""Sends a HEAD request.
    
        url: 拟获取页面的url链接.
        **kwargs: 13个控制访问的参数.
        """
        return request('head', url, **kwargs)
    
    def post(url, data=None, json=None, **kwargs):
        r"""Sends a POST request.
    
        url/data/json,**kwargs: 11个控制访问的参数.
        """
        return request('post', url, data=data, json=json, **kwargs)
    
    def put(url, data=None, **kwargs):
        r"""Sends a PUT request.
    
        url/data,**kwargs: 12个控制访问的参数.
        """
        return request('put', url, data=data, **kwargs)
    
    def patch(url, data=None, **kwargs):
        r"""Sends a PATCH request.
    
        url/data,**kwargs: 12个控制访问的参数.
        """
        return request('patch', url, data=data, **kwargs)
    
    def delete(url, **kwargs):
        r"""Sends a DELETE request.
    
        url,**kwargs: 13个控制访问的参数.
        """
        return request('delete', url, **kwargs)

    3. 爬取网页的通用代码框架

    网络连接有风险,异常处理很重要

    异常 说明
    requests.ConnectionError 网络连接异常,如DNS查询失败、拒绝连接等
    requests.HTTPError HTTP错误异常
    requests.URLRequired URL缺失异常
    requests.TooManyRedirects 超过最大重定向次数,产生重定向异常
    requests.ConnectTimeout 连接远程服务器超时异常
    requests.Timeout 请求URL超时,产生异常

     通用框架:

    import requests
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()      #如果状态不是200,引发异常
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return "产生异常"
    
    if __name__ == "__main__":
        url = "http://www.baidu.com"
        print(getHTMLText(url))

    4. 实例

    实例1:京东商品页面的爬取

    import requests
    url = "https://item.jd.com/6685410.html"
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()  # 如果状态不是200,引发异常
        r.encoding = r.apparent_encoding
        print(r.text[0:1000])
    except:
        print("爬取失败")

     实例2:亚马逊商品页面的爬取。通过headers字段是代码模拟浏览器向http提交请求。

    import requests
    url = "https://www.amazon.cn/dp/B07DBZZPQL/ref=cngwdyfloorv2_recs_0?pf_rd_p=4940946c-0b2b-498c-9e03-31cf7dae70ec&pf_rd_s=desktop-2&pf_rd_t=36701&pf_rd_i=desktop&pf_rd_m=A1AJ19PSB66TGU&pf_rd_r=YENXHWZT81QNMXW27C8B&pf_rd_r=YENXHWZT81QNMXW27C8B&pf_rd_p=4940946c-0b2b-498c-9e03-31cf7dae70ec"
    try:
        kv = {'user-agent' : 'Mozilla/5.0'}
        r = requests.get(url, headers=kv)
        r.raise_for_status()  # 如果状态不是200,引发异常
        r.encoding = r.apparent_encoding
        print(r.text[1000:2000])
    except:
        print("爬取失败")
    

    实例3:百度360搜索关键字提交

    百度关键词接口:http://www.baidu.com/s?wd=keyword 

    360关键词接口:http://www.so.com/s?q=keywork

    import requests
    keyword = 'python'
    url = "http://www.baidu.com/s"
    try:
        kv = {'wd' : keyword}
        r = requests.get(url, params=kv)
        r.raise_for_status()
        print(r.request.url)
        print(len(r.text))
    except:
        print("爬取失败")
    

    实例4:网络图片的爬取和存储

    网络图片的连接格式:http://www.example.com/picture.jpg ,获取的图片为二进制格式

    import requests
    import os
    url = "http://image.ngchina.com.cn/2018/1127/20181127013714400.jpg"
    root = "D://pics//"
    path = root + url.split('/')[-1]
    try:
        if not os.path.exists(root):
            os.mkdir(root)
        if not os.path.exists(path):
            r = requests.get(url)
            with open(path, 'wb') as f:
                f.write(r.content)
                f.close()
                print("文件保存成功")
        else:
            print("文件已经存在")
    except:
        print("爬取失败")
    

    实例5:IP地址的归属地自动查询

    查询IP的链接格式:http://www.ip138.com/ips138.asp?ip=ipaddress

    import requests
    url = "http://www.ip138.com/ips138.asp?ip="
    try:
        r = requests.get(url + '202.204.80.112')
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        print(r.text[-2500:-1500])
    except:
        print("爬取失败")
    

     

    5. 网络爬虫的“盗亦有道”

    1. 网络爬虫引发的问题

    网络爬虫的尺寸

    小规模,数据量小,爬取速度不敏感,Requests库

    中规模,数据规模较大,爬取速度敏感,Scrapy库 大规模,搜索引擎,爬取速度关键,定制开发
    爬取网页,玩转网页 爬取网站,爬取系列网站 爬取全网 

    (1)骚扰问题:受限于编程水平和目的,网络爬虫将会为web服务器带来巨大的资源开销。

    (2)法律风险:服务器上的数据有产权归属,网络爬虫获取数据后牟利将会带来法律风险

    (3)隐私泄露:网络爬虫可能具备突破简单访问控制的能力,获得被保护数据从而泄露个人隐私

    2. 网络爬虫的限制

    (1)来源审查:判断User-Agent进行限制

    检查来访HTTP协议头的User-Agent域,只响应浏览器或友好爬虫的访问。

    (2)发布公告:Robots

    Robots协议:

    Robots Exclusion Standard 网络爬虫排除标准

    作用:告知所有爬虫网站的爬取策略,要求爬虫遵守。

    形式:在网站的根目录下的robots.txt文件

    使用:自动或人工识别robots.txt,再进行内容爬取,协议可以不遵守,但可能存在法律风险

    类人类行为可不遵守,如写小程序一天访问几次服务器

     

    二、网络爬虫之提取

    1.Beautiful Soup库

    Beautiful Soup库是解析、遍历、维护“标签树”的功能库。

    解析器有:html.parser, lxml, xml, html5lib

    格式化显示:soup.prettify(),自动为标签间添加换行符。bs4将读入的文件或者字符串转换为"utf-8"。

    BeautifulSoup类的基本元素

    基本元素 说明
    Tag 标签,最基本的信息组织单元,分别用<>和</>表明开头和结尾
    Name 标签的名字,<p></p>的名字是'p',格式:<tag>.name
    Attributes 标签的属性,字典的组织形式,格式:<tag>.attrs
    NavigableString 标签内非属性字符串,<>...</>中的字符串,格式:<tag>.string
    Comment 标签内字符串的注释部分,一种特殊的Comment类型

    标签树的遍历

      属性 说明
    下行 .contents 子节点列表,将<tag>所有儿子节点存入列表
    .children 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
    .descendants 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
    上行 .parent 节点的父亲标签
    .parents 节点先辈标签的迭代类型,用于循环 遍历先辈节点
    平行 .next_sibling 返回按照HTML文本顺序的下一个平行节点标签
    .previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
    .next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
    .previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

    2. 信息组织与提取方法

    信息标记的形式:

       

               

    实例:

      

    比较:

    XML 最早的通用信息标记语言,可扩展性好,但是繁琐 Internet上的信息交互与传递
    JSON 信息有类型,适合程序处理,较XML简洁 移动应用云端和节点的信息通信,无注释
    YAML 信息无类型,文本信息比例最高,可读性好 各类系统配置文件有注释易读

    信息提取的一般方法:

    (1)完整解析信息的标记形式,再提取关键信息。XML,JSON,YAML

    需要标记解析器,如bs4库的标签树遍历,优点是信息解析准确,缺点是提取过程繁琐

    (2)无视标记信息,直接搜索关键信息。搜索

    使用对信息的文本查找函数即可。优点是提取过程简洁,速度快,缺点是提取信息的准确性与信息内容直接相关。

    融合方法:完整形式解析+搜索,提取关键信息,需要标记解析器及文本查找函数。

    实例:提取HTML所有URL链接

    思路 :1)搜索到所有<a>标签,

                2)解析<a>标签格式,提取href后的链接内容

    url = "http://python123.io/ws/demo.html"
    r = requests.get(url)
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    for link in soup.find_all('a'):
        print(link.get('href'))
    --------------out---------------
    http://www.icourse163.org/course/BIT-268001
    http://www.icourse163.org/course/BIT-1001870001

    bs4库中HTML内容的查找方法:

    <>.find_all(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
    #返回一个列表类型,存储查找的结果
    name:对标签名称的检索字符串
    attrs:对标签属性值的检索字符串,可标注属性检索
    recursive:是否对子孙全部搜索,默认为True
    string: <>...</>中字符串区域的检索字符串
    
    soup.find_all('a')
    soup.find_all(['a','b'])
    soup.find_all(True)            #返回所有标签
    soup.find_all('p', 'course')   #所有属性是course的p标签
    soup.find_all(id='link1')      #查找包含属性id='link1'的标签
    简写形式:
    <tag>(..) 等价于 <tag>.find_all(..)

    3. 实例:中国大学排名定向爬虫

    功能:爬取http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html网站上的大学排名信息,输出排名,学校及总分

    步骤:1)从网络上获取大学排名网页信息:getHTMLText()

               2)提取网页内容中信息到合适的数据结构(关键,二维结构):fillUnivList()

               3)利用数据结构展示并输出结果:printUnivList

    import requests
    import bs4
    from bs4 import BeautifulSoup
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout = 30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, 'html.parser')
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr.find_all('td')
                ulist.append([tds[0].string,tds[1].string,tds[3].string])
    
    def printUnivList(ulist, num):
        tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
        print(tplt.format("排名", "学校名称", "总分", chr(12288)))
        for i in range(num):
            u = ulist[i]
            print(tplt.format(u[0], u[1], u[2], chr(12288)))
    
    def main():
        uinfo = []
        url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
        html = getHTMLText(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 3)
    
    if __name__ == "__main__":
        main()
    '''out
        排名    	   学校名称   	    总分    
        1     	   清华大学   	   95.9   
        2     	   北京大学   	   82.6   
        3     	   浙江大学   	    80 
    '''

    4、正则表达式入门

    regular expression :用来简洁表达一组字符串的表达式。

    编译:将符合正则表达式语法的字符串转换成正则表达式特征:p = re.compile( regex ), 特征可以表达一组字符串

    常用操作符

    操作符 说明 实例
    . 表示任何单个字符  
    [ ] 字符集,对单个字符给出取值范围 [abc],表示a,b,c,[a-z]表示a到z的单个字符
    [^ ] 非字符集,对单个字符给出排除范围 [^abc]表示非a或b或c的单个字符
    * 前一个字符0次或无限次扩展 abc*表示ab,abc,abccccc等
    + 表示前一个字符一次或无限次扩展 abc+表示abc,abcc,abccc等
    ? 前一个字符0次或1次扩展 abc?表示ab,abc
    | 左右表达式任取其一 abc|def表示abc、def
    {m} 扩展前一个字符m次 ab{2}c表示abbc
    {m,n} 扩展前一个字符m至n次(含n) ab{1,2}c表示abc,abbc
    ^ 匹配字符串开头 ^abc表示abc且在一个字符串的开头
    $ 匹配字符串结尾 abc$表示abc且在一个字符串结尾
    () 分组标记,内部只能使用|操作符 (abc)表示abc,(abc|def)表示abc,def
    \d 数字,等价于[0-9]  
    \w 单词字符,等价于[A-Za-z0-9_]  

    经典正则表达式实例:

    正则表达式 内容
    ^[A-Za-z]+$ 由26个字母组成的字符串
    ^[A-Za-z0-9]+$ 由26个字母和数字组成的字符串
    ^-?\d+$ 整数形式字符串
    ^[0-9]*[1-9][0-9]*$ 正整数形式字符串
    [1-9]\d{5} 中国境内邮政编码
    [\u4e00-\u9fa5] 匹配中文字符
    \d{3}-\d{8}|\d{4}-\d{7} 国内电话号码:010-68913536
    (([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]) IP地址

     

    正则表达式的类型

    • raw string类型(原生字符串类型,不包含转义符的类型):r'text', 如r'\d{3}-\d{8}|\d{4}-\d{7}'
    • string类型,将\理解为转义符,使用更繁琐:如'\\d{3}-\\d{8}|\\d{4}-\\d{7}'
    • 当正则表达式包含转义字符,使用raw string类型 

    Re库主要功能函数: 

    函数 说明
    re.search(pattern,string,flags=0) 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
    re.match(pattern,string,flags=0) 从一个字符串的的开始位置起匹配正则表达式,返回match对象
    re.findall(pattern,string,flags=0) 搜索字符串,以列表类型返回全部能匹配的字符串
    re.split(pattern,string,maxsplit=0,flags=0) 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
    re.finditer(pattern,string,flags=0) 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
    re.sub(pattern,repl,string,count=0,flags=0) 在一个字符串中替换所有匹配正则表达式的字串,返回替换后的字符串

    Re库的另一种等价用法

    # 函数式用法:一次性操作
    rst = re.search(r'[1-9]\d{5}', 'BIT 100081')
    # 面向对象用法:编译后的多次操作
    pat = re.compile(r'[1-9]\d{5}')
    rst = pat.search('BIT 100081')
    
    # 真正的正则表达式
    regex = re.compile(pattern, flags = 0)

    Re库的match对象

    属性 说明 方法 说明
    .string 待匹配文本 .group(0) 获得匹配后的字符串
    .re 匹配时使用的pattern对象(正则表达式) .start() 匹配字符串在原始字符串的开始位置
    .pos 正则表达式搜索文本的开始位置 .end() 匹配字符串在原始字符串的结束位置
    .endpos 正则表达式搜索文本的结束位置 .span() 返回(.start(), .end())

    贪婪匹配和最小匹配:

    Re库默认采用贪婪匹配,即输出匹配最长的字串。

    # 贪婪匹配 
    match = re.search(r'PY.*N', 'PYANBNCNDN')
    
    # 最小匹配 
    match = re.search(r'PY.*?N', 'PYANBNCNDN')

    最小匹配操作符

    操作符 说明
    *? 前一个字符0次或无限次扩展,最小匹配
    +? 前一个字符1次或无限次扩展,最小匹配
    ??

    前一个字符0次或1次扩展,最小匹配

    {m,n}? 扩展一个字符m至n次(含n),最小匹配

    5.实例:当当网比价定向爬虫

    目的:获取淘宝搜索页面信息,提取其中的商品名称和价格

    难点:淘宝的搜索接口

    技术路线:request - BeautifulSoup

    程序结构设计: 1)提交商品搜索请求,循环获取页面

                              2)对于每个页面,提取商品名称和价格信息

                              3)将信息输出到屏幕上

    import requests
    from bs4 import BeautifulSoup
    import csv
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout = 30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return("")
    
    def parsePage(ilt, html):
        try:
            soup = BeautifulSoup(html, 'html.parser')
            div_tag = soup.find(name='div', attrs={'dd_name':"普通商品区域"})
            li_tag = div_tag.find_all(name='li')
            for each_goods_li in li_tag:
                price = each_goods_li.find(name = 'span', attrs={'class':"price_n"}).string[1:]
                name = each_goods_li.find(name='a', attrs={'dd_name': r"单品标题"}).attrs['title']
                ilt.append([price,name])
        except:
            print("")
    
    def printGoodsList(ilt):
        tplt = "{:4}\t{:8}\t{:16}"
        print(tplt.format("序号","价格", "商品名称"))
        count = 0
        for g in ilt:
            count += 1
            print(tplt.format(count, g[0], g[1]))
    
    def saveGoods(ilt):
        if(len(ilt) != 0):
            headers = ["序号","价格", "商品名称"]
            with open('goods.csv','w',encoding='utf-8') as f:
                f_csv = csv.writer(f)
                f_csv.writerow(headers)
                for i in range(len(ilt)):
                    row = [i+1,ilt[i][0],ilt[i][1]]
                    f_csv.writerow(row)
    
    def main():
        goods = '书包'
        depth = 3
        start_url = 'http://search.dangdang.com/?key=' + goods + '&page_index='
        infoList = []
        for i in range(depth):
            try:
                url = start_url + str(i+1)
                html = getHTMLText(url)
                parsePage(infoList, html)
            except:
                continue
        printGoodsList(infoList)
        saveGoods(infoList)
    
    if __name__ == "__main__":
        main()

    实例:股票数据定向爬虫

    目标:获取上交所和深交所所有股票的名称和交易信息

    输出:保存到文件中

    候选网站: 1)新浪股票:http://finance.sina.com.cn/stock/ (可能js生成,不太合适)

                     2)百度股票:https://gupiao.baidu.com/stock/

    选取原则:股票信息存在于HTML页面中,非js代码生成,没有Robots协议限制。

    程序设计结构:1)从东方财富网获取股票列表

                             2)根据股票列表逐个到百度股票获取个股信息

                             3)将结果存储到文件

    import  requests
    from bs4 import BeautifulSoup
    import traceback
    import re
    
    def getHTMLText(url, code='utf-8'):
        try:
            r = requests.get(url, timeout = 30)
            r.raise_for_status()
            r.encoding = code
            return r.text
        except:
            return("")
    
    def getStockList(lst, stockURL):
        html = getHTMLText(stockURL, 'GB2312')
        soup = BeautifulSoup(html, 'html.parser')
        a = soup.find_all('a')
        for i in a:
            try:
                href = i.attrs['href']
                lst.append(re.findall(r'[s][hz]\d{6}', href)[0])
            except:
                continue
    
    def getStockInfo(lst, stockURL, fpath):
        count = 0
        for stock in lst:
            url = stockURL + stock + '.html'
            html = getHTMLText(url)
            try:
                if html == "":
                    continue
                infoDict = {}
                soup = BeautifulSoup(html, 'html.parser')
                stockInfo = soup.find('div', attrs={ 'class':"stock-bets"})
                name = stockInfo.find_all(attrs={ 'class':"bets-name"})[0]
                infoDict.update({'股票名称':name.text.split()[0]})
                keyList = stockInfo.find_all('dt')
                valueList = stockInfo.find_all('dd')
                for i in range(len(keyList)):
                    key = keyList[i].text
                    value = valueList[i].text
                    infoDict[key] = value
                with open(fpath, 'a', encoding='utf-8') as f:
                    f.write(str(infoDict) + '\n')
                    count += 1
                    print('\r当前速度:{:.2f}%'.format(count*100/len(lst)), end='')
            except:
                #traceback.print_exc()
                count += 1
                print('\r当前速度:{:.2f}%'.format(count * 100 / len(lst)), end='')
                continue
    
    def main():
        stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
        stock_info_url = 'https://gupiao.baidu.com/stock/'
        output_file = 'D://BaiduStockInfo.txt'
        slist = []
        getStockList(slist,stock_list_url)
        getStockInfo(slist,stock_info_url,output_file)
    if __name__ == '__main__':
        main()

    三、Scrapy爬虫框架

    Scrapy爬虫框架介绍

    scrapy不是一个简单的函数功能库,而是一个爬虫框架: 5+2结构

    框架解析:

    使用 模块 功能
    不需要用户修改 Engine 框架核心,控制所有模块之间的数据流;根据条件触发事件。
    Downloader 根据请求下载网页
    Scheduler 对所有爬取请求进行调度管理
    需要用户修改 Downloader Middleware

    实施Engine、Scheduer和Downloader之间进行用户可配置的控制

    修改、丢弃、新增请求或响应

    Spider

    解析Downloader返回的响应(Response)

    产生爬取项,产生额外的爬取请求

    Item Piplines

    以流水线方式处理Spider产生的爬取项

    操作包括:清理,检验,查重,存储数据

    Spider Middleware 对请求和爬取项再处理

    Requests VS Scrapy

    相同点 不同点 选择

    1)页面请求和爬取两个重要技术路线;

    2)可用性好,文档丰富,入门简单;
    3)都没有处理js、提交表单、应对验证码等功能(可扩展)。
    Requests Scrapy

    1)非常小的需求:requests库

    2)不太小:Scrapy,持续,周期爬取信息,积累形成库

    3)定制程度很高:自搭框架,requests>Scrapy

    页面级爬虫 网站级爬虫
    功能库 框架
    并发性考虑不足,性能较差 并发性好,性能较高
    重点在于页面下载 重点在于爬虫结构
    定制灵活 一般定制灵活,深度定制困难
    上手十分简单 入门稍难

    常用命令:

    命令 说明 格式
    startproject 创建一个新工程 scrapy startproject<name>[dir]
    genspider 创建一个爬虫 scrapy genspider [options] <name><domain>
    settings 获得爬虫配置信息 scrapy settings [options]
    crawl 运行一个爬虫 scrapy crawl<spider>
    list 列出工程中所有爬虫 scrapy list
    shell 启动URL调试命令行 scrapy shell [url]

    步骤:

    1)建立一个Scrapy爬虫工程:scrapy startproject python123demo

    2)在工程中产生一个Scrapy爬虫:scrapy genspider demo python123.io

    3)配置产生的spider爬虫demp.py

    简化版

    import scrapy
    
    class DemoSpider(scrapy.Spider):
        name = 'demo'
        #allowed_domains = ['python123.io']
        start_urls = ['http://python123.io/ws/demo.html']
    
        def parse(self, response):
            fname = response.url.split('/')[-1]
            with open(fname, 'wb') as f:
                f.write(response.body)
            self.log("Save file %s." % fname)

    完整版:

    import scrapy
    
    class DemoSpider(scrapy.Spider):
        name = 'demo'
    
        def start_requests(self):
            urls = [
                'http://python123.io/ws/demo.html'
            ]
            for url in urls:
                yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            fname = response.url.split('/')[-1]
            with open(fname, 'wb') as f:
                f.write(response.body)
            self.log("Save file %s." % fname)
    

    4)运行爬虫,获取网页:scrapy crawl demo

    使用步骤:

    1) 创建一个工程和Spider模板

    数据类型:

    Request类

    Response类

    Item类

    2) 编写Spider
    3) 编写Item Pipleline
    4)优化配置策略

    1)Request类

    class scrapy.http.Request(): 表示一个http请求,由Spider生成,由Downloader执行

    属性或方法 说明
    .url Request对应的请求的URL地址
    .method 对应的请求方法,'Get',‘POST’等
    .headers 字典类型请求风格头
    .body 请求内容主体,字符串风格
    .meta 用户添加的扩展信息,在Scrapy内部模块间传递信息使用
    .copy() 复制该请求


    2)Response类

    class. scrapy.http.Response():表示一个http响应。由Downloader生成,由Spider处理

    属性或方法 说明
    .url Response对应的URL地址
    .status HTTP状态码,默认是200
    .headers Response对应的头信息
    .body Response 对应的内容信息,字符串类型
    .flags 一组标记
    .request 产生Response类型对应的Request对象
    .copy() 复制该响应

    3)Item类

    class scrapy.item.Item(): Item对象表示一个从HTML中提取的信息内容,由Spider生成,由Item Pipeline处理。类似字典类型,可以按照字典类型操作

    Scrapy爬虫支持多种HTML信息提取方法:Beautiful Soup, lxml, re, XPath Selector, CSS Selector

    实例:Scrapy获取上交所和深交所所有股票的名称和交易信息

    百度股票:https://gupiao.baidu.com/stock/

    单个股票:https://gupiao.baidu.com/stock/sz002439

    东方财富网:http://quote.eastmoney.com/stocklist.html

    1)建立工程和spider模板
    >scrapy startproject BaiduStocks
    >cd BaiduStocks
    >scrapy genspider stocks baidu.com
    >修改spiders/stocks.py文件
    2)编写spider
    >配置stocks.py文件
    >修改对返回页面的处理
    >修改对新增URL爬取请求的处理
    3)编写Pipelines
    >配置pipelines.py文件
    >d定义对爬取项的处理类
    >配置ITEM_PIPLINES选项

    stocks.py

    # -*- coding: utf-8 -*-
    import scrapy
    import re
    
    class StocksSpider(scrapy.Spider):
        name = 'stocks'
        start_urls = ['http://quote.eastmoney.com/stocklist.html']
    
        def parse(self, response):
            for href in response.css('a::attr(href)').extract():
                try:
                    stock = re.findall(r"[s][hz]\d{6}", href)[0]
                    url = "https://gupiao.baidu.com/stock/"+ stock + '.html'
                    yield scrapy.Request(url, callback=self.parse_stock)
                except:
                    continue
    
        def parse_stock(self, response):
            infoDict = {}
            stockInfo = response.css('.stock-bets')
            name = stockInfo.css('.bets-name').extract()[0]
            keyList = stockInfo.css('dt').extract()
            valueList = stockInfo.css('dd').extract()
            for i in range(len(keyList)):
                key = re.findall(r'>.*</dt', keyList[i])[0][1:-5]
                try:
                    val = re.findall(r'\d+\.?.*</dd', valueList[i])[0][0:-5]
                except:
                    val = '--'
                infoDict[key] = val
            infoDict.update({'股票名称': re.findall('\s.*\(',name)[0].split()[0] +
                             re.findall('\>.*\<',name)[0][1:-1]})
            yield infoDict
    

    pipelines.py, 修改settings.py中的内容,关联BaidustocksInfoPipline

    class BaidustocksInfoPipline(object):
        def open_spider(self, spider):
            self.f = open('BaiduStockInfo.txt', 'w')
    
        def close_spide(self, spider):
            self.f.close()
    
        def process_item(self, item, spider):
            try:
                line = str(dict(item)) + '\n'
                self.f.write(line)
            except:
                pass
            return item

     

     

     

     

    展开全文
  • 基于网络爬虫数据挖掘算法的web招聘数据分析

    前言

    这个项目是在学校做的,主要是想对各大招聘网站的招聘数据进行分析,没准能从中发现什么,这个项目周期有些长,以至于在项目快要结束时发现网上已经有了一些相关的项目,我后续会把相关的项目材料放在我的GitHub上面,链接为:https://github.com/roguesir ,项目主要分为以下几项:数据获取与处理、探索性数据分析、数据挖掘算法建模等,这篇blog先介绍数据获取与处理。

    数据获取

    系统环境

    Mac OS系统,python3.6

    网站分析

    各个招聘网站的结构不同,进行正则匹配的方式也不同,本项目供爬取了前程无忧、智联招聘、拉勾网等多家招聘网站的web数据,以51job为例进行介绍:
    前程无忧的招聘页面如下图所示,项目最终想要得到的数据包括岗位名称、工作地点、薪资待遇、岗位介绍、公司性质等信息,实际上需要两次爬取页面,第一次爬取搜索页面获得URL,第二次通过URL爬取相关信息。第一次使用Python的urllib和requests库实现,第二次使用Python的BeautifulSoup库实现。
    这里写图片描述

    岗位详情介绍

    爬虫编写

    起初的爬虫代码设置如下

    # -*- coding:utf-8 -*-
    from bs4 import BeautifulSoup
    import sys
    import importlib
    importlib.reload(sys)
    
    def get_html_page(lst,html):
        res = requests.get(html)
        res.encoding = 'gbk'
        soup = BeautifulSoup(res.text, 'html.parser')
        for job in soup.select('.tHjob'):
            position = job.select('h1')[0]['title']
            print(position)
            lst.append(position)
            location = job.select('.lname')[0].text
            lst.append(location)
            salary = job.select('strong')[0].text
            lst.append(salary)
            companyname = job.select('a')[0]['title']
            if len(companyname) > 0:
                lst.append(companyname)
            property = job.select('.ltype')[0].text
            lst.append(property)
        for comp in soup.select('.tCompany_main'):
            experience = comp.select('.sp4')[0].text
            lst.append(experience)
            education = comp.select('.sp4')[1].text
            lst.append(education)
            number = comp.select('.sp4')[2].text
            lst.append(number)
            introduce = comp.select('.tmsg')[0].text
            lst.append(introduce)
        return lst
    
    def write_txt(content):
        with open('raw-cs-info1.txt','a') as f:
            for item in content:
                f.write(item+'\n')
    
    def main():
        print('running main')
        for url in open('web-mis-url1-1.txt'):
            print(url)
            lst = []
            content = get_html_page(lst, url)
            write_txt(content)
        print('Finished!')
    
    main()

    后来发现对于个别网页,这样跑会挂掉,有的匹配不成功就会出问题,于是将代码做了修改:

    try:
        for job in soup.select('.tHjob'):
            position = job.select('h1')[0]['title']
            print(position)
            if len(position)<1:   
                lst.append(discribe[0])
            else:
                lst.append('null')
    except:
        lst.append('null')

    上面的代码实现了对出现问题的匹配进行异常捕获,出现异常的匹配直接在文本中写入null,而不会中断程序,对每个属性进行设置,最终只需要对文本中的null进行处理就OK了。

    数据处理

    基本预处理

    爬虫爬下来的数据基本上还算干净,只有个别的匹配出现失误,这可能由于网站html标签不规则导致,这个问题在爬取前程无忧时候出现了,在智联招聘等网站没有出现。

    # coding=utf-8
    import re
    
    with open('new098.txt','a') as f:
        for line in open('cs-job-discribe.txt'):
            new_line = line.replace('<br>','')
            new_line = re.sub(r'<.+>','',line)
            new_line = re.sub(r'[0-9][0-9]\-[0-9][0-9].+','',new_line)
            f.write(new_line)
            '''
            if len(new_line)==1:
                new_line = re.sub(r'\s',',',new_line)  # 将样本中的\空格\t\v\n\f等用','替换
            f.write(new_line)
            '''

    网页html中本身带有的\空格\v\f\t\n等,写入文档会显示,因此需要进行预处理,把爬取下来的数据规范化。

    数据重复问题:

    由于项目是从不同的招聘网站上爬取数据,存在同一条招聘信息出现多次的情况,需要进行去重处理,另外,全部信息存储在cs-info.xlsx文件中,另将每个属性的数据存储在txt文件中,其中存在大量重复数据需要进行去重处理。

    总结

    在此过程中出现的一些问题进行说明:
    (1)编码问题:在设置了utf-8编码的情况下,爬取保存的数据仍然会出现乱码现象,需要设置html.decode=’gbk’才能解决。
    (2)使用时也尝试了用requests和urllib库实现匹配提取,这个用在岗位描述信息匹配上比较好,代码如下:

    import re
    import requests
    import urllib
    
    res = requests.get(html)
    res.encoding = 'gbk'
    try:
        a = urllib.urlopen(html) 
        html = a.read()
        html = html.decode('gbk')
    
        reg = re.compile(r'<div class="bmsg job_msg inbox.*?<br>(.*?)<div class="mt10">',re.S)
        discribe = re.findall(reg,html)
        print discribe[0]
        # print(discribe)
        lst.append(discribe[0])
    except:
        lst.append('null')
    展开全文
  • 爬虫数据提取与清洗

    千次阅读 2019-11-08 00:07:50
    爬虫的原理 访问网站的时候,客户端会向服务器发送请求,服务器会回复响应数据爬虫就是通过抓取响应数据并进行清理而获取信息。
  • 基于音悦台网站榜单的数据爬取与分析 本实验代码:进入 一、研究背景 在互联网发展初期,网站相对较少,信息查找比较容易。然而伴随互联网爆炸性的发展,普通网络用户想找到所需的资料简直如同大海捞针,这时为满足...
  • Python网络爬虫与信息提取

    千次阅读 2020-05-17 15:28:15
    Python网络爬虫与信息提取 掌握定向网络数据爬取和网页解析的基本能力 几个部分: Requests库的介绍,通过这个库克以自动爬取HTML页面,在网络上自动提交相关请求 robots.txt协议,网络爬虫的规则,网络爬虫...
  • 4、Robots协议(Robts Exclusion Standard,网络爬虫排除标准),其作用是网站告知网络爬虫哪些页面可以抓取,哪些不行,形式是在网站根目录下的robots.txt文件。 5、Robots协议基本语法 # 注释,*代表所有...
  • 大家好,我是老表阅读文本大概需要 4分钟课程简介推荐两个公开课,在中国大学Mooc上都被评为国家精品公开课,完全免费学习。授课老师是北京理工大学嵩天博士Python网络爬虫与数据分析是...
  • 本文介绍 Python数据分析网络爬虫入门基础的内容。 网络通信基础知识 1.网络通信 OSI参考模型 TCP/IP的分层模型 OSI协议参考模型,是基于国际标准化组织(ISO)的建议发展起来的。 它分为7个层次:应用层、表示...
  • Python网络爬虫与信息提取 淘宝商品比价定向爬虫
  • Python爬虫以及数据可视化分析

    万次阅读 多人点赞 2020-12-25 17:43:30
    Python爬虫以及数据可视化分析之B站动漫排行榜信息爬取分析 简书地址:https://www.jianshu.com/u/40ac87350697 简单几步,通过Python对B站番剧排行数据进行爬取,并进行可视化分析 源码文件可以参考Github上传的...
  • Python 爬虫数据分析实战

    万次阅读 多人点赞 2018-04-12 10:41:43
    本课程是 Python 爬虫数据分析项目实战课程,主要分 3 部分: 第 1 部分是 Python 爬虫,主要使用 Urllib 3 和 BeautifulSoup 抓取天猫商城和京东商城胸罩销售数据,并保存到 SQLite 数据库中; 第 2 部分是对...
  • 测验1: Python网络爬虫之规则 (第1周) 1. Requests库中,下面哪个最可能是由于URL格式错误造成异常?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬ A requests.HTTPError B requests.TooMany...
  • Python网络爬虫数据采集实战:基础知识

    千次阅读 多人点赞 2020-03-01 21:58:25
    在进行正式的爬虫之前有必要熟悉以下爬虫的基本概念,例如爬虫的基本原理、网络通信原理以及Web三件套的相关知识等。 目录 一、爬虫原理 1.获取网页 2.提取信息 3.保存数据 4.自动化程序 二、HTTPS 1.URL ...
  • Python网络爬虫与信息提取(实例讲解)

    千次阅读 多人点赞 2020-03-18 21:59:31
    下面小编就为大家带来一篇Python网络爬虫与信息提取(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 课程体系结构: 1、Requests框架:自动爬取HTML页面自动网络请求...
  • 1. 下面哪个不是“网络爬虫与信息提取”相关的技术路线?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪...
  • python网络爬虫与信息提取 课程分为以下6个部分 requests 自动爬取html页面,自动网络请求提交 robots.txt 网络爬虫排除标准 beautiful soup 解析html页面 projects 实战项目A/B Re 正则表达式详解,提取...
  • 作为一名数据分析师而并非开发工程师,需要掌握的爬虫必备的知识内容,能获取需要的数据即可。如果需要更专业的基于爬虫工程师的内容请浏览我的其他文章。 爬虫的网页抓取 1.爬虫的用途 实现浏览器的功能,通过制定的...
  • 测验3: Python网络爬虫之实战 (第3周) 1. 以下不是正则表达式优势的选项是:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬...
  • Python网络爬虫与信息提取MOOC 测验4: Python网络爬虫之框架 (第4周) 1、下面哪个不是“网络爬虫与信息提取”相关的技术路线?‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬...
  • 爬虫实战01——利用python爬虫并进行数据分析 爬取链家二手房相关信息并进行数据分析 {https://sh.lianjia.com/ershoufang/pg} 一、爬虫部分 背景 需求来源于生活 大数据时代来临,数据就是核心,数据就是...
  • 一、前言 距上次更新博客,又过去很长时间了,感觉再不更新一下,自己写博客的...二、《平凡的荣耀》数据爬取与分析 1 简介 旨在实现对翻拍电视剧《平凡的荣耀》综合热度的分析,计划设计数据爬取模块、数据分析模块
  • Python 网络爬虫系列笔记是笔者在学习嵩天老师的《Python网络爬虫与信息提取》课程及笔者实践网络爬虫的笔记。 课程链接:Python网络爬虫与信息提取 参考文档: Requests 库官方文档 Beautiful Soup 库官方文档 ...
  • Python网络爬虫和信息提取

    千次阅读 2020-03-16 23:39:06
    Python网络爬虫和信息提取 微信关注公众号:夜寒信息 致力于为每一位用户免费提供更优质技术帮助资源供给,感谢支持!     一直没有去学习爬虫,如今去试着去学习一下爬虫,体验一番网上冲浪的乐趣,哈哈。 ...
  • 正则表达式是处理字符串的强大工具,它有自己特定的语法结构,对于爬虫来说,它可以帮我们从HTML例提取我们想要的信息,实际上正则表达式应用非常广泛,如数据挖掘、数据分析网络爬虫、输入有效性验证等。...
  • 网络爬虫之框架1.scrapy爬虫框架介绍1.1.scrapy爬虫框架介绍安装方法: 简要地说,Scrapy不是一个函数功能库,而是一个快速功能强大的网络爬虫框架。 (爬虫框架是实现爬虫功能的一个软件结构和功能组件集合,是一...
  • Python网络爬虫数据采集实战:同花顺动态网页爬取

    千次阅读 多人点赞 2020-03-09 12:42:31
    之后对源代码进行信息提取进而存储即可,本文则针对动态网页进行数据采集,首先介绍Ajax相关理论,之后实战爬取同花顺动态网页,获取个股相关信息。 目录 一、Ajax理论 1.Ajax简介 2.Ajax分析 3.Ajax提取 二...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,421
精华内容 7,768
关键字:

网络爬虫的数据提取与分析

爬虫 订阅