精华内容
下载资源
问答
  • 常见爬虫场景
    2022-04-27 16:29:11

    1.普通网页爬取

    demo:娱乐淘金-虎嗅网 (huxiu.com)

    爬取demo:zhugezifang/webmagic-collector (github.com)

    2.js 动态渲染网页爬取

    通过 Quick Javascript Switcher - Chrome 网上应用店 (google.com) 进行判断是不是js 渲染的页面

    demo:豆瓣电影 (douban.com)

    3.app爬虫---抓包工具

    Charles抓包 - 简书 (jianshu.com)

    更多相关内容
  • 常见的几种爬虫数据采集场景

    前嗅每天都接到很多数据采集的需求,虽然来自不同行业、网站及企业,不过各需求的采集场景都有很多类似之处。小编结合大家的数据采集需求,总结了以下几种爬虫常见的数据采集场景。

    1.实时采集并更新新增数据

    对于很多舆情或政策监测的数据采集需求,大多都需要实现实时采集,并且只采集新增数据。这样才能快速监测到需要的数据,提高监测速度和质量。

    ForeSpider数据采集软件可设置不间断采集,7×24H不间断采集指定网站,已入库数据不重复采集,实时更新网站中的新增数据,之前采集的数据不会重复入库,无需每天重新采集数据,大大提高数据采集效率,节约网络带宽和代理IP资源。

    设置介绍:

    ①定时采集

    定时采集:设置任务定时设置,可在某个时间点定时启动/停止采集,或在某一时间段后定时启动/停止采集。

    ②增量采集:每次只采集更新的链接,只重采更新链接,不重采数据页面。

    这样爬虫软件不仅可以自动采集,实时更新,还能自动排重保证数据采集高效稳定运行。

    2.自动补采遗漏数据

    在爬虫采集数据的过程中,经常会由于网络异常、加载异常、网站反爬等原因,导致采集过程中遗漏部分数据的情况。

    针对这种情况,就需要将采集过程中采集失败的请求,重新补采一遍,从而高效获取全量数据。

    ForeSpider数据采集系统针对于这种常见的采集场景,可以进行数据补采的设置,从而提高采集效率,快速获取全量数据。

    设置介绍:

    ①自定义采集策略:选择采集入库失败、采集错误和上次未采集数据。设置后重新采集,即可快速补采之前的遗漏数据,无需重复采集耗时耗力。

    ②设置加载日志宏:可以按照任务ID值、任务数据大小等,对不符合采集要求的数据,通过筛选日志列表,进行重新采集,以补采存在遗漏的数据。

    例如,有些网站封IP的方式是重定向一个新的网址,因此采集状态显示成功,但任务的数据质量一般很小,比如2KB,这种情况可以通过加载日志宏中,加载质量过小的任务日志的方式,来重新补采这部分任务。

    3.定时采集数据

    一个很常见的数据采集需求就是,每天定点开始爬取一个或多个网站,为了解放双手,定时采集数据就非常必要了。

    ForeSpider数据采集系统可设置定时开始、停止采集,时间点与时间段兼并设置,可在某个时间点定时启动/停止采集,或在某一时间段后定时启动/停止采集。减少人力重复工作,有效避免手动采集的情况。

    设置介绍:

    ①间隔定时采集:设定间隔时间,实现固定间隔时间的采集开启/关闭。

    ②定点定时采集:设定爬虫自动开始/关闭的时间。

    示例

    ①每天采集新增数据

    每天定时采集新增数据,设置每天某时间点采集新增数据,设置好后,即可每天定点采集,节省人工成本。

    ②网站反爬

    当采集一段时间以后获取不到数据,过一段时间又可以获取数据。可开启采集后,根据反爬规律,设置某时间段后停止采集,设置某时间段后开始采集,即可有效避免反爬,高效采集数据。

    ③自动更新数据库

    部署到服务器上以后,需要每天采集网站新数据到本地数据库,可开始定时采集,每天在固定的时间采集数据。

    4.批量关键词搜索

    我们经常需要采集某网站上某行业、某事件、某主体等相关内容,这时就会用到关键词采集,来采集批量关键词搜索出来的数据。

    ForeSpider数据采集软件可实现多种关键词检索采集的方式。

    ①批量导入关键词,采集在目标网站中搜索关键词出来的数据内容,还可对关键词进行排重处理,方便快捷,无需写脚本即可批量采集关键词搜索出来的数据。

    ②关键词存在外部数据库中,实时调用采集。通过ForeSpider爬虫软件连接到其他数据库的数据表,或爬虫软件中的其他数据表,可使用动态变化的关键词库,实时检索采集数据。

    ③通过接口实时传输关键词。可以将用户数据中实时产生的检索词,通过接口传输到ForeSpider数据采集系统中,进行实时关键词检索采集。并将采集到的数据,实时传输回用户系统中,进行显示。

    设置介绍:

    关键词配置:可进行关键词配置,可在高级配置中配置各项参数。

    关键词列表:批量导入、修改关键词批量导入删除、修改关键词,还可对关键词进行排重处理。

      

    示例

    ①采集关键词搜索的网站

    例如百度、360问答、微博搜索等所有具有搜索功能的网站。

    ②关键词充当词库,调用使用

    例如某网站不同地区分类的网址中包含地区参数,可直接将地区参数导入关键词列表,写简单的脚本,调用关键词拼写不同地区分类的网站,从而让配置更加简单。

    ③用户输入检索词,实时爬取数据返回显示

    用户输入需要检索的词汇后,实时传入ForeSpider爬虫软件中,进行现场查询采集,并将采集到的数据实时传输回用户的系统中去,向用户展示数据。

    5.自定义筛选文件大小/类型

    我们经常需要采集网页中的图片、视频以及各种附件等数据,为了获取更加精准的数据,需要对文件的大小/类型有更精确的筛选。

    前嗅ForeSpider采集软件,可自行设置采集文件上下限或文件类型,从而筛选采集网页中符合条件的文件数据。

    例如:采集某网页中大小在2b以上的文件数据、采集网页中所有的text数据、采集页面中image数据、采集文件中video数据等。

    设置介绍:

    设置过滤:设置采集文件的类型,采集该类型的文件数据,设置采集文件大小下限,以过滤小文件,设置采集文件大小阈值,以过滤大文件。

    示例

    ①采集网页中所有图片数据

    需要网页中所有图片数据,或部分图片数据时,在文件设置中选择采集文件类型,然后配置采集,节省配置成本,实现精准采集。

    ②采集网页中所有视频数据

    需要采集网页中所有视频数据,或部分视频数据时,在文件设置中选择采集文件类型,然后配置采集。

    ③采集网页中特定文件数据

    通过设置采集文件大小下限值,将小文件、无效文件过滤掉,实现精准采集。

    6.登录采集

    当采集需要登录的网站上的数据时,就需要登录设置。前嗅ForeSpider数据采集分析引擎可采集需要登录(帐密登录、扫描登录、短信验证登录)的网站、APP数据,采集登录后可见的数据。

    ForeSpider爬虫软件,可设置自动登录,也可手动设置登录,还可以使用Cookie进行登录,多种登录配置方式适合各种登录场景,灵活配置。

    概念介绍:

    Cookie:Cookie指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据。Cookie基于Internet的各种服务系统应运而生,是由Web服务器保存在用户浏览器上的小文本文件,它可以包含有关用户的信息,是用户获取、交流、传递信息的主要场所之一,爬虫可以模拟cookie进行登录采集。

    设置介绍:

    ①登录配置:可自动配置,也可手动配置。

    ②Cookie设置:对于需要cookie的网站,可自动生成cookie,获取数据。也可手动添加cookie,获取数据。

    示例:

    适用于任何需要登录(帐密登录、扫描登录、短信验证登录)的网站、APP数据。

    7.批量网站批量配置

    大部分的企业级大数据项目,往往需要采集的很多网站,少则数百,多则上千万,每个网站分别单独配置也是不现实的,这时候就需要对成千上万的网站进行批量配置并采集。

    ForeSpider爬虫软件专门针对这种情况,独创智能配置算法和采集配置语言,能够高效配置采集和解析网页结构,采集大批量结构类似的网站数据,无需每个网站依次配置,即可实现同时采集成千上万网站。

    用户将需要采集的网址列表输入到一个采集任务中,通过对采集内容进行智能识别,即可实现一个配置采集模板以采集成千上万网站的需求。 

    优势:

    ①节约大量人工配置成本:无需人工一个个网站依次配置,即可实现采集成千上万网站的需求。

    ②短时间内采集大批量网站,功能上线快:快速实现网站数据扩张,短时间内即可采集海量数据,缩短项目上线时间。

    ③采集数据多、范围广:一次性实现海量网站的采集需求,批量管理大规模数据,实现企业级数据采集能力。

    ④数据便于管理:数据高度集中管理,便于全局监测数据采集情况,方便运维。

    ⑤灵活删减采集源:对于不想继续采集的来源可以随时删除,有新的采集来源便于随时批量增加。

    示例

    ①舆情监测

    短时间内迅速实现对大量媒体网站的数据监测,迅速形成与某事件/某主体相关的内容监测。

    ②内容发布平台

    收集批量网址,海量采集某方面的内容,对数据分类后对应发布。

    ③行业信息库

    迅速建立某行业相关信息资料库,以备查询使用。

    看到这里,大家应该对爬虫的采集场景有了一个深入的了解。后期我们将结合各采集场景,为大家展示更多的采集案例,请您敬请期待。

    l 前嗅简介

    前嗅大数据,国内领先的研发型大数据专家,多年来致力于为大数据技术的研究与开发,自主研发了一整套从数据采集、分析、处理、管理到应用、营销的大数据产品。前嗅致力于打造国内第一家深度大数据平台!

    展开全文
  • 常见的python应用场景及三方库.zip 机器学习 人工智能AI 爬虫 数据可视化 图形界面 游戏开发 数据分析 数据处理 python三方库总览.doc
  • 爬虫常见面试

    万次阅读 多人点赞 2019-06-12 20:30:05
    1.你写爬虫的时候都遇到过什么反爬虫措施,你最终是怎样解决的 通过headers反爬虫:解决策略,伪造headers 基于用户行为反爬虫:动态变化去爬取数据,模拟普通用户的行为, 使用IP代理池爬取或者降低抓取频率,或 ...

    一.项目问题:

    1.你写爬虫的时候都遇到过什么反爬虫措施,你最终是怎样解决的

    • 通过headers反爬虫:解决策略,伪造headers
    • 基于用户行为反爬虫:动态变化去爬取数据,模拟普通用户的行为, 使用IP代理池爬取或者降低抓取频率,或 通过动态更改代理ip来反爬虫
    • 基于动态页面的反爬虫:跟踪服务器发送的ajax请求,模拟ajax请求,selnium
      和phtamjs。或 使用selenium + phantomjs 进行抓取抓取动态数据,或者找到动态数据加载的json页面。
    • 验证码 :使用打码平台识别验证码
    • 数据加密:对部分数据进行加密的,可以使用selenium进行截图,使用python自带的pytesseract库进行识别,但是比较慢最直接的方法是找到加密的方法进行逆向推理。

    2.你写爬虫的时候 使用的什么框架 选择这个框架的原因是什么?
    scrapy。
    优势:

    • 可以实现高并发的爬取数据, 注意使用代理;

    • 提供了一个爬虫任务管理界面, 可以实现爬虫的停止,启动,调试,支持定时爬取任务;

    • 代码简洁

      劣势:

    • 1.可扩展性不强。

    • 2.整体上来说: 一些结构性很强的, 定制性不高, 不需要太多自定义功能时用pyspider即可, 一些定制性高的,需要自定义一 些 功能时则使用Scrapy。

    2.scrapy框架专题部分(很多面试都会涉及到这部分)

    (1)请简要介绍下scrapy框架。

    scrapy 是一个快速(fast)、高层次(high-level)的基于 python 的 web 爬虫构架,
    用于抓取web站点并从页面中提取结构化的数据。scrapy 使用了 Twisted异步网络库来
    处理网络通讯
    

    (2)为什么要使用scrapy框架?scrapy框架有哪些优点?

    • 它更容易构建大规模的抓取项目
    • 它异步处理请求,速度非常快
    • 它可以使用自动调节机制自动调整爬行速度

    (3)scrapy框架有哪几个组件/模块?简单说一下工作流程。

    • Scrapy Engine:
      这是引擎,负责Spiders、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等等!(像不像人的身体?)

    • Scheduler(调度器): 它负责接受引擎发送过来的requests请求,并按照一定的方式进行整理排列,入队、并等待Scrapy
      Engine(引擎)来请求时,交给引擎。

    • Downloader(下载器):负责下载Scrapy
      Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy
      Engine(引擎),由引擎交给Spiders来处理,

    • Spiders:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器),

    • Item
      Pipeline:它负责处理Spiders中获取到的Item,并进行处理,比如去重,持久化存储(存数据库,写入文件,总之就是保存数据用的)

    • Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件

    • Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spiders中间‘通信‘的功能组件(比如进入Spiders的Responses;和从Spiders出去的Requests)
      在这里插入图片描述
      工作流程:

    数据在整个Scrapy的流向:

    程序运行的时候,

    引擎:Hi!Spider, 你要处理哪一个网站?

    Spiders:我要处理23wx.com

    引擎:你把第一个需要的处理的URL给我吧。

    Spiders:给你第一个URL是XXXXXXX.com

    引擎:Hi!调度器,我这有request你帮我排序入队一下。

    调度器:好的,正在处理你等一下。

    引擎:Hi!调度器,把你处理好的request给我,

    调度器:给你,这是我处理好的request

    引擎:Hi!下载器,你按照下载中间件的设置帮我下载一下这个request

    下载器:好的!给你,这是下载好的东西。(如果失败:不好意思,这个request下载失败,然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载。)

    引擎:Hi!Spiders,这是下载好的东西,并且已经按照Spider中间件处理过了,你处理一下(注意!这儿responses默认是交给def parse这个函数处理的)

    Spiders:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,这是我需要跟进的URL,将它的responses交给函数 def xxxx(self, responses)处理。还有这是我获取到的Item。

    引擎:Hi !Item Pipeline 我这儿有个item你帮我处理一下!调度器!这是我需要的URL你帮我处理下。然后从第四步开始循环,直到获取到你需要的信息,

    注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy会重新下载。)

    以上就是Scrapy整个流程了。
    官方语言版本:
    流程
    1.引擎打开一个域名,蜘蛛处理这个域名,并让蜘蛛获取第一个爬取的URL。

    2.引擎从蜘蛛那获取第一个需要爬取的URL,然后作为请求在调度中进行调度。

    3.引擎从调度那获取接下来进行爬取的页面。

    4.调度将下一个爬取的URL返回给引擎,引擎将他们通过下载中间件发送到下载器。

    5.当网页被下载器下载完成以后,响应内容通过下载中间件被发送到引擎。

    6.引擎收到下载器的响应并将它通过蜘蛛中间件发送到蜘蛛进行处理。

    7.蜘蛛处理响应并返回爬取到的项目,然后给引擎发送新的请求。

    8.引擎将抓取到的项目项目管道,并向调度发送请求。

    系统重复第二步后面的操作,直到调度中没有请求,然后断开引擎与域之间的联系

    4.scrapy的去重原理(指纹去重到底是什么原理)
    在这里插入图片描述在这里插入图片描述

    • 需要将dont_filter设置为False开启去重,默认是False;
    • 对于每一个url的请求,调度器都会根据请求的相关信息加密得到一个指纹信息,并且将指纹信息和set()集合中得指纹信息进行比对,如果set()集合中已经存在这个数据,就不在将这个Request放入队列中。如果set()集合中没有,就将这个Request对象放入队列中,等待被调度。

    5.scrapy中间件有几种类,你用过哪些中间件*
    scrapy的中间件理论上有三种:

    • Schduler Middleware,

    • Spider Middleware,

    • Downloader Middleware),

    • 在应用上一般有以下两种:

      1.爬虫中间件Spider Middleware

      主要功能是在爬虫运行过程中进行一些处理.

      2.下载器中间件Downloader Middleware

      主要功能在请求到网页后,页面被下载时进行一些处理.
      使用
      1.Spider Middleware有以下几个函数被管理:
      process_spider_input 接收一个response对象并处理,

      位置是Downloader–>process_spider_input–>Spiders(Downloader和Spiders是scrapy官方结构图中的组件)
      process_spider_exception spider出现的异常时被调用
      process_spider_output 当Spider处理response返回result时,该方法被调用

      process_start_requests 当spider发出请求时,被调用
      位置是Spiders–>process_start_requests–>Scrapy Engine(Scrapy Engine是scrapy官方结构图中的组件)

    2.Downloader Middleware有以下几个函数被管理

     - process_request  request通过下载中间件时,该方法被调
    
       
    
     - process_response 下载结果经过中间件时被此方法处理
    
      
    
     - process_exception 下载过程中出现异常时被调用
    

    6.scrapy中间件再哪里起的作用

    • 1.爬虫中间件Spider Middleware:主要功能是在爬虫运行过程中进行一些处理.爬虫发起请求request的时候调用,列如更换修改代理ip,修改UA,

    • 2.下载器中间件Downloader Middleware:主要功能在请求到网页后,页面被下载时进行一些处理.浏览器返回响应response的时候调用,无效的数据,特殊情况进行重试

    三.代理问题:

    1.为什么会用到代理
    一些网站会有相应的反爬虫措施,例如很多网站会检测某一段时间某个IP的访问次数,如果访问频率太快以至于看起来不像正常访客,它可能就会会禁止这个IP的访问。所以我们需要设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。
    2.代理怎么使用(具体代码, 请求在什么时候添加的代理)

    1,可以使用urllib2中的ProxyHandler来设置代理ip

    1 import urllib2
     2 
     3 # 构建了两个代理Handler,一个有代理IP,一个没有代理IP
     4 httpproxy_handler = urllib2.ProxyHandler({"http" : "124.88.67.81:80"})
     5 nullproxy_handler = urllib2.ProxyHandler({})
     6 #定义一个代理开关
     7 proxySwitch = True 
     8 # 通过 urllib2.build_opener()方法使用这些代理Handler对象,创建自定义opener对象
     9 # 根据代理开关是否打开,使用不同的代理模式
    10 if proxySwitch:  
    11     opener = urllib2.build_opener(httpproxy_handler)
    12 else:
    13     opener = urllib2.build_opener(nullproxy_handler)
    14 
    15 request = urllib2.Request("http://www.baidu.com/")
    16 
    17 # 使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理。
    18 response = opener.open(request)
    19 
    20 # 就是将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理。
    21 # urllib2.install_opener(opener)
    22 # response = urlopen(request)
    23 
    24 print response.read()
    

    2,使用requets代理

     1 import requests
     2 
     3 # 根据协议类型,选择不同的代理
     4 proxies = {
     5   "http": "http://12.34.56.79:9527",
     6   "https": "http://12.34.56.79:9527",
     7 }
     8 
     9 response = requests.get("http://www.baidu.com", proxies = proxies)
    10 print response.text
    

    3.代理失效了怎么处理

    事先用检测代码检测可用的代理,每隔一段时间更换一次代理,如果出现302等状态码,
    则立即更换下一个可用的IP。
    
    1 1、将代理IP及其协议载入ProxyHandler赋给一个opener_support变量;
    2、将opener_support载入build_opener方法,创建opener;
    3、安装opener。具体代码如下:from urllib import requestdef ProxySpider
    (url, proxy_ip, header):opener_support =
     request.ProxyHandler({'http': proxy_ip})
      opener = request.build_opener(opener_support)
       request.install_opener(opener) req =
     request.Request(url, headers=header)rsp =
      request.urlopen(req).read()return rsp
    

    四.验证码处理:

    1.登陆验证码处理

    图片验证码:先将验证码图片下载到本地,然后使用云打码识别;
    滑动验证码:使用selenium模拟人工拖动,对比验证图片的像素差异,
    找到滑动的位置然后获取它的location和size,然后 top,bottom,left,
    right = location['y'] ,location['y']+size['height']+ location['x'] +
     size['width'] ,然后截图,最后抠图填入这四个位置就行。
    

    **2.爬取速度过快出现的验证码处理

    设置setting.py中的DOWNLOAD_DELAY,降低爬取速度;
    
    用xpath获取验证码关键字,当出现验证码时,识别验证码后再继续运行。
    

    3.如何用机器识别验证码**
    对接打码平台

    • 对携带验证码的页面数据进行抓取
    • 将页面中的验证码进行解析, 将验证码图片下载到本地
    • 将验证码图片提交给打码平台进行识别, 返回识别后的结果

    云打码平台使用:

    • 在官网中进行普通用户和开发者用户注册
    • 登录开发者用户:

    a) 示例代码下载:开发文档 --> 调用示例及最新DLL --> PythonHTTP示例下载

    b) 创建一个软件:我的软件 --> 添加新的软件(后期会使用该软件的秘钥和id)

    使用示例代码中的示例代码对保存本地的验证码进行识别

    五.模拟登陆问题:

    1.模拟登陆流程

    
     1. 加载浏览器driver; 获取登录页面; 使用css选择器或者xpath找到账号和密码输入框,
    	并发送账号和密码;
     2. 如果出现验证码则需要先识别验证码,在模拟输入验证码或者模拟鼠标拖动;
     3. 使用css选择器或者xpath找到登录按钮,使用click模拟点击;
    
    

    2.cookie如何处理

     
    
     1. 采用selenium自动登录获取cookie,保存到文件;
     2. 读取cookie,比较cookie的有效期,若过期则再次执行步骤1;
     3. 在请求其他网页时,填入cookie,实现登录状态的保持;
    
    

    3.如何处理网站传参加密的情况**

    加密的三种情况:
    
     1. 加密+访问次数限制+每个页面相关信息的条目需要点详情进行二次请求;
     2. 复杂的加密算法进行参数+时间戳+sig值,后台进行 参数+时间限制;
     3. 定时同步cookie+每个界面一个cookie。
    
    破解方法:
    
     1. 使用selenium模拟点击获取详情页面;
     2. 获取其相应的api接口,GET接口URL,获取它的json表格内容;
     3. 反向分析网页JS加载内容;
    
    

    六.分布式

    1.什么是分布式

    需要计算的数据量大,任务多,一台机器搞不定或者效率极低,需要多台机器共同协作(而不是孤立地各做各的,所以需要通信),最后所有机器完成的任务汇总在一起,完成大量任务.

    将一个项目拷贝到多台电脑上,同时爬取数据

    分布式爬虫则是将多台主机组合起来,共同完成一个爬取任务,这将大大提高爬取的效率。

    记住爬虫的本质是网络请求和数据处理,如何稳定地访问网页拿到数据,如何精准地提取出高质量的数据才是核心问题
    2.分布式原理
    分布式爬虫主要由主机与从机,我们把自己的核心服务器(主机)称为 master,而把用于跑爬虫程序的机器(从机)称为 slave。

    我们首先给爬虫一些start_urls,spider 最先访问 start_urls 里面的 url,再根据我们的 parse 函数,对里面的元素、或者是其他的二级、三级页面进行抓取。而要实现分布式,只需要在这个starts_urls里面做文章就行了。进一步描述如下:

    1. master 产生 starts_urls,url 会被封装成 request 放到 redis 中的
      spider:requests,总的 scheduler 会从这里分配 request,当这里的 request 分配完后,会继续分配
      start_urls 里的 url。
    2. slave 从 master 的 redis 中取出待抓取的 request,下载完网页之后就把网页的内容发送回 master 的
      redis,key 是 spider:items。scrapy 可以通过 settings 来让 spider
      爬取结束之后不自动关闭,而是不断的去询问队列里有没有新的 url,如果有新的 url,那么继续获取 url
      并进行爬取,所以这一过程将不断循环。
    3. master 里的 reids 还有一个 key 是 “spider:dupefilter” 用来存储抓取过的 url 的
      fingerprint(使用哈希函数将url运算后的结果),防止重复抓取,只要 redis 不清空,就可以进行断点续爬。

    scrapy实现分布式抓取简单点来说

    • 可以借助scrapy_redis类库来实现。
    • 在分布式爬取时,会有master机器和slave机器,其中,master为核心服务器,slave为具体的爬虫服务器。
    • 我们在master服务器上搭建一个redis数据库,并将要抓取的url存放到redis数据库中,所有的slave爬虫服务器在抓取的时候从redis数据库中去链接,由于scrapy_redis自身的队列机制,slave获取的url不会相互冲突,然后抓取的结果最后都存储到数据库中。master的redis数据库中还会将抓取过的url的指纹存储起来,用来去重。相关代码在dupefilter.py文件中的request_seen()方法中可以找到。
    • 捅过重写scheduler和spider类,实现了调度、spider启动和redis的交互。实现新的dupefilter和queue类,达到了判重和调度容器和redis的交互,因为每个主机上的爬虫进程都访问同一个redis数据库,所以调度和判重都统一进行统一管理,达到了分布式爬虫的目的。

    3.分布式如何判断爬虫已经停止了

    1 spider.getStatus();//获取爬虫状态
    2 spider.getStatus().equals(Spider.Status.Init);//运行中
    

    4.分布式的去重原理

    分布式去重问题:
    Duplication Filter:
    Scrapy中用集合实现这个request去重功能,Scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。这个核心的判重功能是这样实现的:

        def request_seen(self, request):
            # self.request_figerprints 就是一个指纹集合  
            fp = self.request_fingerprint(request)
            # 这就是判重的核心操作  
            if fp in self.fingerprints:
                return True
            self.fingerprints.add(fp)
            if self.file:
                self.file.write(fp + os.linesep)
    

    在scrapy-redis中去重是由Duplication Filter组件来实现的,它通过redis的set 不重复的特性,巧妙的实现了Duplication Filter去重。scrapy-redis调度器从引擎接受request,将request的指纹存⼊redis的set检查是否重复,并将不重复的request push写⼊redis的 request queue。
    引擎请求request(Spider发出的)时,调度器从redis的request queue队列⾥里根据优先级pop 出⼀个request 返回给引擎,引擎将此request发给spider处理。

    总结:

    1、最后总结一下scrapy-redis的总体思路:这套组件通过重写scheduler和 spider类,实现了调度、spider启动和redis的交互。
    2、实现新的dupefilter和queue类,达到了判重和调度容器和redis 的交互,因为每个主机上的爬虫进程都访问同一个redis数据库, 所以调度和判重都统一进行统一管理,达到了分布式爬虫的目的。
    3、当spider被初始化时,同时会初始化一个对应的scheduler对象, 这个调度器对象通过读取settings,配置好自己的调度容器queue 和判重工具dupefilter。
    4、每当一个spider产出一个request的时候,scrapy引擎会把这个 reuqest递交给这个spider对应的scheduler对象进行调度, scheduler对象通过访问redis对request进行判重,如果不重复就 把他添加进redis中的调度器队列里。当调度条件满足时,scheduler 对象就从redis的调度器队列中取出一个request发送给spider, 让他爬取。
    5、当spider爬取的所有暂时可用url之后,scheduler发现这个spider 对应的redis的调度器队列空了,于是触发信号spider_idle, spider收到这个信号之后,直接连接redis读取start_urls池,拿 去新的一批url入口,然后再次重复上边的工作。

    七.数据存储和数据库问题:
    1.关系型数据库和非关系型数据库的区别
    在这里插入图片描述
    详情请点击:https://blog.csdn.net/hzp666/article/details/79168675
    2.爬下来数据你会选择什么存储方式,为什么
    Redis基于内存,读写速度快,也可做持久化,但是内存空间有限,当数据量超过内存空间时,需扩充内存,但内存价格贵;
    MySQL基于磁盘,读写速度没有Redis快,但是不受空间容量限制,性价比高;

    大多数的应用场景是MySQL(主)+Redis(辅),MySQL做为主存储,Redis用于缓存,加快访问速度。需要高性能的地方使用Redis,不需要高性能的地方使用MySQL。存储数据在MySQL和Redis之间做同步;
    MongoDB 与 MySQL 的适用场景:
    MongoDB 的适用场景为:数据不是特别重要(例如通知,推送这些),数据表结构变化较为频繁,数据量特别大,数据的并发性特别高,数据结构比较特别(例如地图的位置坐标),这些情况下用 MongoDB , 其他情况就还是用 MySQL ,这样组合使用就可以达到最大的效率。
    今天我们可以通过第三方平台(如:Google,Facebook等)可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL数据库的发展也却能很好的处理这些大的数据。

    3.各种数据库支持的数据类型,和特点
    MongoDB

    • MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
    • 它是一个内存数据库,数据都是放在内存里面的。
    • 对数据的操作大部分都在内存中,但 MongoDB 并不是单纯的内存数据库。
    • MongoDB 是由 C++ 语言编写的,是一个基于分布式文件存储的开源数据库系统。
    • 在高负载的情况下,添加更多的节点,可以保证服务器性能。
    • MongoDB 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

    MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
    优点:
    1.性能优越:快速!在适量级的内存的 MongoDB 的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快,
    2.高扩展:第三方支持丰富(这是与其他的 No SQL 相比,MongoDB 也具有的优势)
    3.自身的 Failover 机制!
    4.弱一致性(最终一致),更能保证用户的访问速度
    5.文档结构的存储方式,能够更便捷的获取数据: json 的存储格式
    6.支持大容量的存储,内置 GridFS
    7.内置 Sharding
    8.MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
    MongoDB 缺点:
    主要是无事物机制!

    ① MongoDB 不支持事务操作(最主要的缺点)
    ② MongoDB 占用空间过大
    ③ MongoDB 没有如 MySQL 那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方
    redis
    Redis 一个内存数据库,通过 Key-Value 键值对的的方式存储数据。由于 Redis 的数据都存储在内存中,所以访问速度非常快,因此 Redis 大量用于缓存系统,存储热点数据,可以极大的提高网站的响应速度。
    1、Redis优点
    (1)支持数据的持久化,通过配置可以将内存中的数据保存在磁盘中,Redis 重启以后再将数据加载到内存中;
    (2)支持列表,哈希,有序集合等数据结构,极大的扩展了 Redis 用途;
    (3)原子操作,Redis 的所有操作都是原子性的,这使得基于 Redis 实现分布式锁非常简单;
    (4)支持发布/订阅功能,数据过期功能;
    Redis的数据类型
    Redis通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
    Redis 一个内存数据库,通过 Key-Value 键值对的的方式存储数据。由于 Redis 的数据都存储在内存中,所以访问速度非常快,因此 Redis 大量用于缓存系统,存储热点数据,可以极大的提高网站的响应速度。
    1、Redis优点
    (1)支持数据的持久化,通过配置可以将内存中的数据保存在磁盘中,Redis 重启以后再将数据加载到内存中;
    (2)支持列表,哈希,有序集合等数据结构,极大的扩展了 Redis 用途;
    (3)原子操作,Redis 的所有操作都是原子性的,这使得基于 Redis 实现分布式锁非常简单;
    (4)支持发布/订阅功能,数据过期功能;
    mysql
    MySQL是关系型数据库。
    MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
    MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
    系统特性
    1. [2] 使用 C和 C++编写,并使用了多种编译器进行测试,保证了源代码的可移植性。
    2.支持 AIX、FreeBSD、HP-UX、Linux、Mac OS、NovellNetware、OpenBSD、OS/2 Wrap、Solaris、Windows等多种操作系统。
    3.为多种编程语言提供了 API。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby,.NET和 Tcl 等。
    4.支持多线程,充分利用 CPU 资源。
    5.优化的 SQL查询算法,有效地提高查询速度。
    6.既能够作为一个单独的应用程序应用在客户端服务器网络环境中,也能够作为一个库而嵌入到其他的软件中。
    7.提供多语言支持,常见的编码如中文的 GB 2312、BIG5,日文的 Shift_JIS等都可以用作数据表名和数据列名。
    8.提供 TCP/IP、ODBC 和 JDBC等多种数据库连接途径。
    9.提供用于管理、检查、优化数据库操作的管理工具。
    10.支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
    11.支持多种存储引擎。
    12.MySQL 是开源的,所以你不需要支付额外的费用。
    13.MySQL 使用标准的 SQL数据语言形式。
    14.MySQL 对 PHP 有很好的支持,PHP是比较流行的 Web 开发语言。
    15.MySQL是可以定制的,采用了 GPL协议,你可以修改源码来开发自己的 MySQL 系统。
    16.在线 DDL/更改功能,数据架构支持动态应用程序和开发人员灵活性(5.6新增)
    17.复制全局事务标识,可支持自我修复式集群(5.6新增)
    18.复制无崩溃从机,可提高可用性(5.6新增)
    19.复制多线程从机,可提高性能(5.6新增)
    20.3倍更快的性能(5.7 [3] 新增)
    21.新的优化器(5.7新增)
    22.原生JSON支持(5.7新增)
    23.多源复制(5.7新增)
    24.GIS的空间扩展 [4] (5.7新增)

    优势:

    在不同的引擎上有不同 的存储方式。

    查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。

    开源数据库的份额在不断增加,mysql的份额页在持续增长。

    缺点:

    在海量数据处理的时候效率会显著变慢。

    4.是否支持事务…
    mongo不支持
    redis mysql支持

    八.Python基础问题:

    1.Python2和Python3的区别,如何实现python2代码迁移到Python3环境
    区别:字符串类型、默认字符、print方法、除法的数字类型、导入方式、继承类、元类声明、异常处理、字典、模块合并、部分模块重命名(详情)

    代码迁移:python3有个内部工具叫做2to3.py,位置在Python3/tool/script文件夹。

    首先CD到这个文件夹,然后调用

    py 2to3.py -w f:/xxxx/xxx.py
    

    具体方法:https://blog.csdn.net/xutiantian1412/article/details/79523953

    2.Python2和Python3的编码方式有什么差别

    在python2中主要有str和unicode两种字符串类型,而到python3中改为了bytes和str,并且一个很重要的分别是,在python2中如果字符串是ascii码的话,str和unicode是可以直接进行连接和比较,但是到python3中就不行了,bytes和str是两个独立的类型。另一个重要的是python2中不管是str还是unicode都可以直接写入文件,而不需要加上它是不是str的类型写入方式,但是在python3中如果是写或者读bytes类型就必需带上’b’.
    3.迭代器,生成器,装饰器
    生成器
    创建python迭代器的过程虽然强大,但是很多时候使用不方便。生成器是一个简单的方式来完成迭代。简单来说,Python的生成器是一个返回可以迭代对象的函数。
    为什么使用生成器

    1. 更容易使用,代码量较小

    2. 内存使用更加高效。比如列表是在建立的时候就分配所有的内存空间,而生成器仅仅是需要的时候才使用,更像一个记录

    3. 代表了一个无限的流。如果我们要读取并使用的内容远远超过内存,但是需要对所有的流中的内容进行处理,那么生成器是一个很好的选择,比如可以让生成器返回当前的处理状态,由于它可以保存状态,那么下一次直接处理即可。

    4. 流水线生成器
      最简单的生成器:

    g = (x*x for x in range(10))
    for i in g:
        print i
    

    函数方法实现稍复杂的生成器:

    def fib(max):
        n,a,b=0,1,1
        while n<max:
            yield b
            a,b=b,a+b
            n +=1
    for n in fib(6):
        print n 
    

    迭代器概述
    可以直接作用于for循环的数据类型有以下几种:

    一类是集合数据类型,如list,tuple,dict,set,str等
    一类是generator ,包括生成器和带yeild的generator function
    这些可以 直接作用于for循环的对象统称为可迭代对象:Iterable

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    def hs(n):
        i=0
        while   i<n:
            yield i
            i+=1
    
    a=(hs(1000))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    

    装饰器:
    基本概念:在函数调用前后自动打印日志,又不改变原函数,在代码运行期间动态增加功能的方式称之为“装饰器”。

    装饰器的语法已@开头,接下来是装饰器函数的名字和可选的参数,紧跟着装饰器声明的是被修饰的函数和装饰函数的可选参数。
    **3大特征:**1,外部函数包含内部函数,2,返回一个内部函数,3,内部函数用到外部函数的变量

    import time
    def hs(f):#装饰器的函数,f接受被装饰的函数名
        def neibu():#装饰内部函数
            start=time.time()
            f()#调用被装饰的函数
            end=time.time()
            print(end-start)
        return neibu#装饰器返回内部函数,(内部代表的是包装盒)
    @hs#@加函数名,代表下面的函数被hs装饰
    def jisuan():
        print('123456')
    jisuan()
    

    4.Python的数据类型

    1. Number(数字) 包括int,long,float,complex
    2. String(字符串) 例如:hello,“hello”,hello
    3. List(列表) 例如:[1,2,3],[1,2,3,[1,2,3],4]
    4. Dictionary(字典) 例如:{1:“nihao”,2:“hello”}
    5. Tuple(元组) 例如:(1,2,3,abc)
    6. Bool(布尔) 包括True、False

    九.协议问题:

    robots协议是什么?

    Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。

    1.http协议,请求由什么组成,每个字段分别有什么用,https和http有什么差距
    请求行(request line)、请求头部(header)、空行和请求数据四个部分组成(详情);

    请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本;
    请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息;
    空行,请求头部后面的空行是必须的;
    请求数据也叫主体,可以添加任意的其他数据;
     HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

    HTTPS和HTTP的区别主要如下:

    • https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
    • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
    • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
    • http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

    2.证书问题
    https://blog.csdn.net/fangqun663775/article/details/55189107

    3.TCP,UDP各种相关问题
    https://blog.csdn.net/xiaobangkuaipao/article/details/76793702

    十.数据提取问题:

    1.主要使用什么样的结构化数据提取方式,可能会写一两个例子

    JSON文件
    
    JSON Path
    转化为Python类型进行操作(json类)
    XML文件
    
    转化为Python类型(xmltodict)
    XPath
    CSS选择器
    正则表达式
    

    详情:https://www.cnblogs.com/miqi1992/p/7967399.html

    2.正则的使用
    http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
    文本、电话号码、邮箱地址
    "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}KaTeX parse error: Can't use function '\.' in math mode at position 34: …[a-zA-Z0-9_-]+(\̲.̲[a-zA-Z0-9_-]+)…
    元字符 含义
    . 匹配除换行符以外的任意一个字符
    ^ 匹配行首
    $ 匹配行尾
    ? 重复匹配0次或1 * 重复匹配0次或更多次 + 重复匹配1次或更多次
    {n,} 重复n次或更多次
    {n,m} 重复n~m次
    [a-z] 任意字符
    [abc] a/b/c中的任意一个字符
    {n} 重复n次
    \b 匹配单词的开始和结束
    \d 匹配数字
    \w 匹配字母,数字,下划线
    \s 匹配任意空白,包括空格,制表符(Tab),换行符
    \W 匹配任意不是字母,数字,下划线的字符
    \S 匹配任意不是空白符的字符
    \D 匹配任意非数字的字符
    \B 匹配不是单词开始和结束的位置
    [^a] 匹配除了a以外的任意字符
    [^(123|abc)] 匹配除了123或者abc这几个字符以外的任意字符

    3.动态加载的数据如何提取
    爬取动态页面目前来说有两种方法

    • 分析请求页面

    • 通过Selenium模拟浏览器获取(不推荐这种,太慢)

      分析很简单,我们只需要打开了浏览器F12开发者模式,获取它的js请求文件(除JS选项卡还有可能在XHR选项卡中,当然 也可以通过其它抓包工具)

      我们打开第一财经网看看,发现无法获取元素的内容

      打开Network,看下它的请求,这里我们只看它的 j s 请求就够了, 找到json接口

      将它的url放到浏览器看下,发现是我们要的数据,就可以获取了

      一些网站所有的接口都进行了加密操作,我们无法解析js,就必须采用selenium+phantomjs进行获取

    4.json数据如何提取

    • 采用正则表达式解析:获取整个json数据后,采用正则表达式匹配到关键词;
    • 使用eval解析
    • json.loads() 是把Json格式字符串解码转换成Python对象,如果在json.loads的时候出错,要注意被解码的Json字符的编码,json.dumps() 是把json_obj 转换为json_str

    十一、其他常见面试

    1、Post 和 Get 区别

    • GET数据传输安全性低,POST传输数据安全性高,因为参数不会被保存在浏览器历史或web服务器日志中;
    • 在做数据查询时,建议用GET方式;而在做数据添加、修改或删除时,建议用POST方式;
    • GET在url中传递数据,数据信息放在请求头中;而POST请求信息放在请求体中进行传递数据;
    • GET传输数据的数据量较小,只能在请求头中发送数据,而POST传输数据信息比较大,一般不受限制;
    • 在执行效率来说,GET比POST好

    2、Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

    • 赋值:把等号右边的数据,存储到左边变量所开辟的内存空间中
    • 浅拷贝:只拷贝引用不拷贝对象本身,一旦有一个引用修改,所有的引用都会被迫修改
    • 深拷贝:直接拷贝对象本身,产生一个新的对象,并且产生一个新的引用;就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,不管数据结构多么的复杂,数据之间的修改都不会相互影响
      3、什么是线程和进程?
      进程:一个程序在操作系统中被执行以后就会创建一个进程,通过进程分配资源(cpu、内存、I/O设备),一个进程中会包含一到多个线程,其中有一个线程叫做主线程用于管理其他线程。.一个正在运行的程序可以看做一个进程,进程拥有独立运行所需要的全部资源。(例如:打开QQ相当于开启一个进程)
      线程:程序中独立运行的代码段。在一个进程执行的过程,一般会分成很多个小的执行单位,线程就是这些执行单位;在处理机调度,以线程为单位件进行,多个线程之间并发执行,线程占用的是cpu。
      一个程序至少拥有一个进程,一个进程至少拥有一个线程。进程负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。
      多线程
      多线程定义:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
      多线程优点:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。
      所以为了提高爬虫的效率,我们可以使用多线程来下载文件,在python中我们使用threading模块来创建多线程,从而实现多线程爬虫。(补充:Python3不能再使用thread模块)。
      多线程使用的场合:耗时操作(访问外存,即:I/O,访问网络资源),为了不阻碍主线程或者其他的操作,一般会采用多线程。
      4、爬虫使用多线程好?还是多进程好?为什么?
      对于IO密集型代码(文件处理,网络爬虫),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,会造成不必要的时间等待,而开启多线程后,A线程等待时,会自动切换到线程B,可以不浪费CPU的资源,从而提升程序执行效率)。

    在实际的采集过程中,既考虑网速和相应的问题,也需要考虑自身机器硬件的情况,来设置多进程或者多线程。
    5、什么是协程?
    协程是:在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。他本身是一种特殊的子程序或者称作函数。
    遇到IO密集型的业务时,多线程加上协程,你磁盘在那该读读该写写,我还能去干点别的。在WEB应用中效果尤为明显。
    协程的好处:
    跨平台
    跨体系架构
    无需线程上下文切换的开销
    无需原子操作锁定及同步的开销
    方便切换控制流,简化编程模型
    高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
    6、什么是并行和并发?
    并行:多个进程在同一时刻同时进行
    并发:多个进程在同一时间段内交替进行 (操作系统大多采用并发机制),根据一定的算法(常见的就是时间片轮询算法)
    7,__new)_和__init__的区别

    new:它是创建对象时调用,会返回当前对象的一个实例,可以用_new_来实现单例

    init:它是创建对象后调用,对当前对象的一些实例初始化,无返回值
    8,列举爬虫用到的网络数据包,解析包?

    网络数据包 urllib、urllib2、requests

    解析包 re、xpath、beautiful soup、lxml
    9.如何显著提升爬虫的效率

    1. 使用性能更好的机器

    2. 使用光纤网络

    3. 多进程

    4. 多线程

    5. 分布式

    10.如何提升scrapy的爬取效率
    (1)增加并发
    默认scrapy开启的并发线程为32个, 可以适当进行增加. 在settings配置文件中修改`CONCURRENT_REQUESTS = 100值为100, 并发设置成了为100.

    (2)降低日志级别
    在运行scrapy时, 会有大量日志信息的输出, 为了减少CPU的使用率. 可以设置log输出信息为INFO或者ERROR. 在配置文件中编写: LOG_LEVEL = ‘INFO’

    (3)禁止cookie
    如果不是真的需要cookie, 则在scrapy爬取数据时可以进制cookie从而减少CPU的使用率, 提升爬取效率. 在配置文件中编写: COOKIES_ENABLED = False.

    (4)禁止重试
    对失败的HTTP进行重新请求(重试)会减慢爬取速度, 因此可以禁止重试. 在配置文件中编写: RETRY_ENABLED = False

    (5)减少下载超时
    如果对一个非常慢的链接进行爬取, 减少下载超时可以能让卡住的链接快速被放弃, 从而提升效率. 在配置文件中进行编写: DOWNLOAD_TIMEOUT = 10 超时时间为10s.

    11,使用redis搭建分布式系统时如何处理网络延迟和网络异常?

    • 由于网络异常的存在,分布式系统中请求结果存在“三态”的概念,即三种状态:“成功”、“失败”、“超时(未知)”
    • 当出现“超时”时可以通过发起读取数据的操作以验证 RPC 是否成功(例如银行系统的做法)
    • 另一种简单的做法是,设计分布式协议时将执行步骤设计为可重试的,即具有所谓的“幂等性”

    12.你是否了解mysql数据库的几种引擎?

    • InnoDB:

    InnoDB是一个健壮的事务型存储引擎,这种存储引擎已经被很多互联网公司使用,为用户操作非常大的数据存储提供了一个强大的解决方案。

    在以下场合下,使用InnoDB是最理想的选择:

    1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。

    2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。

    3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。

    4.外键约束。MySQL支持外键的存储引擎只有InnoDB。

    5.支持自动增加列AUTO_INCREMENT属性。

    一般来说,如果需要事务支持,并且有较高的并发读取频率,InnoDB是不错的选择。

    • MEMORY:

    使用MySQL Memory存储引擎的出发点是速度。为得到最快的响应时间,采用的逻辑存储介质是系统内存。

    虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩溃时,所有的Memory数据都会丢失。

    获得速度的同时也带来了一些缺陷。

    一般在以下几种情况下使用Memory存储引擎:

    1.目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。

    2.如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。

    3.存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。

    十二、 Tornado

    什么是RESTful
    全称:Representational State Transfer
    是HTTP协议(1.0和1.1)的主要设计者Roy Thomas Fielding提出
    资源(Resources) 表现层(Representational )状态转化(State Transfer)
    是实现API的一种风格
    RESTful风格
    Resources(资源):使用URL指向一个实体,例如:网页是资源,媒体也是资源
    Representational (表现层):资源的表现形式,例如:图片,HTML文本等
    State Transfer(状态转化):GET, POST, PUT, DELETE HTTP动词操作资源
    例如后端的增删改查,增删改查可以和http请求联系起来
    常用HTTP动词
    RESTful解释:
    GET, POST, PUT, DELETE 分别用来 获取,新建,更新,删除资源
    幂等性:GET, PUT, DELETE
    幂等性是指无论一次还是多次操作都具有一样的副作用
    POST不具有幂等性,因为post每次都创建一个新的,
    对于幂等性操作可以我们可以放心的发多次操作
    对于非幂等性我,我们需要在后台保证发送多次不会创建多次
    Tornado RESTful Api示例
    在这里插入图片描述
    MVC框架:
    M:model表示操作数据库层
    V:view表示视图层
    C:controller 表示业务逻辑层
    我们省略视图层,来实现微服务,进行用户管理(增删改查)

    十三、python基础代码

    画三角形星号

    cs=int(input('请输入层数'))
    for i in range(cs):
        j=1
        while      j<=2*i+1:
            print('*',end='')
            j+=1
        print()
    
    

    #求一个数的倒过来得数

    i=int(input("请输入一个整数:"))
    j=0
    while   i>0:
        j=j*10+i%10
        i//=10
    print(j)
    
    

    求一个元素在列表里出现了几次

    a=[1,2,3,2,1,2,3,4,5,6,4,3,2,1,2,3,4,5,6,5,4,3,5,6,7,8,9,7,8,9,0]
    b=set(a)
    for i in b:
        print('%d在a中出现了%d次'%(i,a.count(i)))
    
    

    查找变量的顺序

    - LEGB法则

    • L-----LOCAL 局部
    • E-------ENCLOSE------嵌套作用域
    • G-------GLOBLE-------全局
    • B---------BUILT-IN------内置
    a=100
    b=2
    c=10
    def waibu():
        b=200
        c=2
        def neibu():
            c=300
            print(c)#LOCAL局部变量
            print(b)#ENCLOSE嵌套
            print(a)#GLOBAL全局
            print(max)#BUILT-IN内置
        neibu()
    waibu()
    
    

    递归阶乘

    def jiecheng(n):
        if  n==1:
            return 1
        else:
            return n*jiecheng(n-1)
    s=jiecheng(5)
    print(s)
    
    a=[lambda x:x*i for i in range(3)]
    print(a[0](3)) # 6
    print(a[1](3)) # 6
    print(a[2](3)) # 6
    
    class   A():
        def __init__(self):
            print('A开始')
            print('A结束')
    class   B(A):
        def __init__(self):
            print('B开始')
            super().__init__()
            print('B结束')
    class   C(A):
        def __init__(self):
            print('C开始')
            super().__init__()
            print('C结束')
    class   D(B,C):
        def __init__(self):
            print('D开始')
            super().__init__()
            print('D结束')
    d=D()
    输出结果为:
    D开始
    B开始
    C开始
    A开始
    A结束
    C结束
    B结束
    D结束
    

    单例

    class   Car():
        def __new__(cls, *args, **kwargs):
            if not hasattr(Car,'inst'):#如果Car里面没有inst属性
                Car.inst=object.__new__(Car)#就建立一个Car对象,给inst属性
            return Car.inst#返回一个属性inst
        def __init__(self,name,cid):
            print('你好')
            self.name=name
            self.cid=cid
    a=Car('宝马','京A66666')
    b=Car('奔驰','京B66666')
    print(a.name,a.cid)
    print(b.name,b.cid)
    输出:
    你好
    你好
    奔驰 京B66666
    奔驰 京B66666
    

    多态

    class   A():
        def j(self):
            print('aaa')
    class   B():
        def j(self):
            print('bbb')
    class   C():
        def j(self):
            print('ccc')
    def e(d):
        d.j()
    f=A()
    g=B()
    k=C()
    e(f)
    e(g)
    e(k)
    

    观察者模式

    class   Resi():
        def __init__(self):
            self.obsv=[]
            self.stautus=''
        def attach(self,ob):
            self.obsv.append(ob)
        def notify(self):
            for x in self.obsv:
                x.update()
    class   Observe():
        def __init__(self,name,rs):
            self.name=name
            self.rs=rs
        def update(self):
            print('%s %s 请不要打游戏了'%(self.rs.status,self.name))
    class   Manager():
        def __init__(self,name,boss):
            self.name=name
            self.boss=boss
        def update(self):
            print('%s %s 请到北京饭店开会'%(self.boss.status,self.name))
    if  __name__=='__main__':
        resi=Resi()
        obj_zs=Observe('张三',resi)
        obj_ls=Observe('李四',resi)
        obj_xh=Observe('小红',resi)
        m_lqd=Manager('刘强东',resi)
        m_my=Manager('马云',resi)
        resi.attach(obj_zs)
        resi.attach(obj_ls)
        resi.attach(obj_xh)
        resi.attach(m_lqd)
        resi.attach(m_my)
        resi.status='老板来啦'
        resi.notify()
    

    策略模式

    class   CashNormal():
        def accept_money(self,money):
            return money
    class   CashRate():
        def __init__(self,rate):
            self.rate=rate
        def accept_money(self,money):
            return money*self.rate
    class   CashReturn():
        def __init__(self,conditon,ret):
            self.conditon=conditon
            self.ret=ret
        def accept_money(self,money):
            return money-(money//self.conditon)*self.ret
    class   Context():
        def __init__(self,cs):
            self.cs=cs
        def get_result(self,money):
           return self.cs.accept_money(money)
    if __name__ == '__main__':
        zd={}
        zd[1]=Context(CashNormal())
        zd[2]=Context(CashRate(0.8))
        zd[3]=Context(CashReturn(300,50))
        celue=int(input('请输入策略'))
        if celue in zd.keys():
            cs=zd[celue]
        else:
            cs=zd[1]
        money=float(input('请输入金额'))
        print(cs.get_result(money))
    

    工厂模式

    class   Bmw():
        def __init__(self,name):
            self.name=name
    class   Benz():
        def __init__(self,name):
            self.name=name
    class   Carfactory:
        @staticmethod
        def makecar(name):
            if name=='宝马':
                return Bmw(name)
            elif    name=='奔驰':
                return Benz(name)
    car=Carfactory.makecar('宝马')
    print(car.name,type(car))
    car1=Carfactory.makecar('奔驰')
    print(car1.name,type(car1))
    

    析构函数

    class   A():
        count=0
        def __init__(self,name):
            self.name=name
            A.count+=1
            print('加上',self.name,'还有%d个对象'%A.count)
        def __del__(self):
            A.count-=1
            print('删除',self.name,'还剩%d个对象'%A.count)
    a=A('张三')
    b=A('李四')
    del a
    del b
    

    二分查找

    # 重要前提:二分查找的前提是有序
    # 例如:【2,5,1,4,1,3】
    # 先排序:【1,1,2,3,4,5】
    # 先拿出列表中间的那个元素,和num进行比较,如果num大于中间的那个元素,
    # 则表明:应该下次在中间和末尾之间的元素查找
    # 如果num小于中间的这个元素,则表明:num在开始的元素和中间元素之间
    list_1=[2,5,1,4,1,3]
    list_1.sort()
    print("排序之后的列表:",list_1)
    num=int(input("请输入你要查找的数字:"))
    first=0
    last=len(list_1)-1
    while   first<last:
        mid=(first+last)//2
        if list_1[mid]==num:
            print("找到了")
            break
        elif    list_1[mid]>num:
            last=mid-1
        elif    list_1[mid]<num:
            first=mid+1
    else:
        print("没找到")
    
    list_1.sort()
    print("拍完序之后的列表为:",list_1)
    num=int(input("请输入你要查找的数字:"))
    first=0
    last=len(list_1)-1
    while   first<last:
        mid=(first+last)//2
        if  list_1[mid]==num:
            print("找到啦")
            break
        elif    list_1[mid]<num:
            first=mid+1
        elif    list_1[mid]>num:
            last=mid-1
    else:
        print("谁知道在哪")
    
    

    冒泡排序

    冒泡排序算法的运作如下:
    比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
    对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    针对所有的元素重复以上的步骤,除了最后一个。
    持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    
    list_1=[2,3,1,5,6,4]
    gs=len(list_1)
    for i in range(0,gs-1):
        for j in range(0,gs-i-1):
            if list_1[j]>list_1[j+1]:
                list_1[j],list_1[j+1]=list_1[j+1],list_1[j]
    print(list_1)
    
    

    空心塔型

    cs = int(input("请输出要打印的层数"))
    for i in range(cs):
        for j in range(cs - i-1):
            print(' ', end='')
        for k in range(2 * i+1):
            if  k==0 or k==2*i or i==cs-1:#条件控制了塔型是否空心
                print('*', end='')
            else:
                print(' ',end='')
        i += 1
        print()
        请输出要打印的层数7
          *
         * *
        *   *
       *     *
      *       *
     *         *
    *************
    
    

    塔型

    
    cs = int(input("请输出要打印的层数"))
    for i in range(cs):
        for j in range(cs - i - 1):
            print(' ', end='')
        for k in range(2 * i + 1):#这里的范围取值决定了塔型每行的字符数
                print('*', end='')
        i += 1
        print()
    
    输出:
           *
          ***
         *****
        *******
       *********
      ***********
     *************
    ***************
    
    展开全文
  • Robots协议(爬虫协议)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。该协议是国际互联网界通行的道德规范,虽然没有写入法律...

    【概述】

    书名:Python网络爬虫从入门到实践(第2版)

    作者:唐松

    日期:2021年08月01日

    读书用时:1568页,100小时,59个笔记

    【读书笔记】

    ◆ 1.2 网络爬虫是否合法

    爬虫协议,行走在法律边缘,触不可及。

    >> Robots协议(爬虫协议)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。该协议是国际互联网界通行的道德规范,虽然没有写入法律,但是每一个爬虫都应该遵守这项协议。

    携程酒店经理的:三月爬虫高峰期的由来。

    >> 因为有大量的大学生五月份交论文,在写论文的时候会选择爬取数据,也就是三月份爬取数据,四月份分析数据,五月份交论文。

    ◆ 1.3 网络爬虫的基本议题

    >> 网络爬虫的流程其实非常简单,主要可以分为三部分:(1)获取网页;(2)解析网页(提取数据);(3)存储数据。

    ◆ 2.1 搭建Python平台

    Anaconda,数据分析专用python工具。

    >> 如果你希望成为数据分析师或者商业分析师,爬虫只是方便之后做数据分析,笔者推荐你使用Anaconda,配合着自带的Jupyter Notebook,这会提升你的分析效率。

    第三方库,可以看作360杀毒软件,你先杀毒不需要自己写杀毒软件,只需要下载它,使用它完成你的部分需求足以。

    >> pip安装第三方库bs4,它可以使用其中的BeautifulSoup解析网页

    ◆ 2.2 Python使用入门

    面向过程编程:好比线性流程写代码,运行逻辑从上到下直接执行,适合临时小需求;

    面向函数编程:好比折中组合写代码,封装需要反复多次使用的模块,适合独立的小业务,每个模块之间无联系;

    面向对象编程:善用初始化函数self.参数,做数据关联,适合接口测试。

    def __init__(self,name,age):

    self.name = name

    self.age = age

    >> 如果各个函数之间独立且无共用的数据,就选用函数式编程;如果各个函数之间有一定的关联性,那么选用面向对象编程比较好。

    直接调用:初始化函数直接赋值指向参数;

    间接调用:通过self.参数传到类的子函数做二次调用,配上self.就可以在全类中全局调用。

    >> 调用被封装的内容时有两种方式:通过对象直接调用和通过self间接调用

    继承的原理:通过比对子类的共同属性,然后封装一个父类,子类天然继承父类的所有属性,可以节约代码,不过读起来需要从后向前读。

    >> 动物:吃喝拉撒

    猫:喵喵叫(猫继承动物的功能)

    狗:汪汪叫(狗继承动物的功能)

    ◆ 2.4 Python实践:基础巩固

    搜索引擎的坑:百度搜索,你会发现很多名字不一样,点进去内容却一样的伪答案,而且时间也乱七八糟需要添加检索条件,最坑的是前几个文章都是百度快照;谷歌相比百度的竞价排名,更多的是通过点击率或者收藏浏览指数排名,好处就是广告不多,缺点就是有的时候看不懂英文。

    >> 就笔者自己的体验而言,谷歌的有效信息检索速度比百度快,较新的回答很有可能是英文的,但是如果你的英文阅读能力不行,就另当别论了。记得使用谷歌搜索时,找到Stack Overflow网站上的回答可以非常快地解决你的问题。

    python基础面试题库

    >> Python基础试题

    有序序列:列表、元祖。

    无序序列:字典。

    >> 对字典进行排序是不可能的,只有把字典转换成另一种方式才能排序。字典本身是无序的,但是如列表元组等其他类型是有序的,所以需要用一个元组列表来表示排序的字典。

    不可更改对象:字符串、数字、元组;

    可变对象:列表、字典。

    >> 这是因为在Python中对象有两种,即可更改(mutable)与不可更改(immutable)对象。在Python中,strings字符串、tuples元组和numbers数字是不可更改对象,而list列表、dict字典等是可更改对象。

    ◆ 第3章 静态网页抓取

    >> 第3章 ◄ 静态网页抓取 ►

    在网站设计中,纯粹HTML格式的网页通常被称为静态网页,早期的网站一般都是由静态网页制作的。在网络爬虫中,静态网页的数据比较容易获取,因为所有数据都呈现在网页的HTML代码中。相对而言,使用AJAX动态加载网页的数据不一定会出现在HTML代码中,这就给爬虫增加了困难。本章先从简单的静态网页抓取开始介绍,第4章再介绍动态网页抓取。

    在静态网页抓取中,有一个强大的Requests库能够让你轻易地发送HTTP请求,这个库功能完善,而且操作非常简单。本章首先介绍如何安装Requests库,然后介绍如何使用Requests库获取响应内容,最后可以通过定制Requests的一些参数来满足我们的需求。

    ◆ 3.2 获取响应内容

    >> 说明如下:

    (1)r.text是服务器响应的内容,会自动根据响应头部的字符编码进行解码。

    (2)r.encoding是服务器内容使用的文本编码。

    (3)r.status_code用于检测响应的状态码,如果返回200,就表示请求成功了;如果返回的是4xx,就表示客户端错误;返回5xx则表示服务器错误响应。我们可以用r.status_code来检测请求是否正确响应。

    (4)r.content是字节方式的响应体,会自动解码gzip和deflate编码的响应数据。

    (5)r.json()是Requests中内置的JSON解码器。

    ◆ 3.3 定制Requests

    get请求,用paramas传参数;

    post请求,用paycloud的json格式和data格式传参数。

    >> 在Requests中,你可以直接把这些参数保存在字典中,用params(参数)构建至URL中。

    >> 编码为表单形式的数据

    ◆ 第4章 动态网页抓取

    >> 动态网页抓取的两种技术:通过浏览器审查元素解析真实网页地址和使用Selenium模拟浏览器的方法。

    ◆ 4.1 动态抓取的实例

    Ajax异步更新技术:通过在后台与服务器进行少量数据交换实现部分内容的更新,有点:不重复下载数据,时间短,更新部分新数据快。

    >> 异步更新技术——AJAX(Asynchronous Javascript And XML,异步JavaScript和XML)。它的价值在于通过在后台与服务器进行少量数据交换就可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下对网页的某部分进行更新。一方面减少了网页重复内容的下载,另一方面节省了流量,因此AJAX得到了广泛使用。

    >> 异步更新技术——AJAX(Asynchronous Javascript And XML,异步JavaScript和XML)。它的价值在于通过在后台与服务器进行少量数据交换就可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下对网页的某部分进行更新。一方面减少了网页重复内容的下载,另一方面节省了流量,因此AJAX得到了广泛使用。

    ajax案例,博客评论的内容:通过js提取数据加载到源代码中进行展示。

    >> 通过JavaScript提取数据加载到源代码进行呈现的。

    ◆ 4.2 解析真实地址抓取

    >> json_string[json_string.find('{'):-2]
 # 从第一个左大括号提取,最后的两个字符-括号和分号不取

    json.loads:把字符串转为json格式。

    >> 使用json.loads可以把字符串格式的响应体数据转化为json数据。

    ◆ 4.3 通过Selenium模拟浏览器抓取

    >> find_elements_by_name

    find_elements_by_xpath

    find_elements_by_link_text

    find_elements_by_partial_link_text

    find_elements_by_tag_name

    find_elements_by_class_name

    find_elements_by_css_selector

    >> 加快Selenium的爬取速度。常用的方法有:

    (1)控制CSS的加载。

    (2)控制图片文件的显示。

    (3)控制JavaScript的运行。

    >> # 控制css
 from selenium import webdriver
 fp = webdriver.FirefoxProfile()
 fp.set_preference("permissions.default.stylesheet",2)
 driver = webdriver.Firefox(firefox_profile=fp, executable_path =r'C:\Users\santostang\Desktop\geckodriver.exe')
 #把上述地址改成你电脑中geckodriver.exe程序的地址
 driver.get("Hello world!")

    >> 控制css的加载主要用fp = webdriver.FirefoxProfile()这个功能

    >> # 限制图片的加载
 from selenium import webdriver
 fp = webdriver.FirefoxProfile()
 fp.set_preference("permissions.default.image",2)
 driver = webdriver.Firefox(firefox_profile=fp, executable_path =r'C:\Users\santostang\Desktop\geckodriver.exe')
 #把上述地址改成你电脑中geckodriver.exe程序的地址
 driver.get("Hello world!")

    >> # 限制JavaScript的执行
 from selenium import webdriver
 fp = webdriver.FirefoxProfile()
 fp.set_preference("javascript.enabled", False)
 driver = webdriver.Firefox(firefox_profile=fp, executable_path =r'C:\Users\santostang\Desktop\geckodriver.exe')
 #把上述地址改成你电脑中geckodriver.exe程序的地址
 driver.get("Hello world!")

    ◆ 第5章 解析网页

    >> 第5章 ◄ 解析网页 ►

    我们已经能够使用requests库从网页把整个源代码爬取下来了,接下来需要从每个网页中提取一些数据。本章主要介绍使用3种方法提取网页中的数据,分别是正则表达式、BeautifulSoup和lxml。

    3种方法各有千秋,想要快速学习的读者可以先挑选一种自己喜欢的方法学习,3种方法都能够解析网页。你也可以先阅读本章的最后一节,在了解3种方法各自的优缺点后,再选择一种方法开始学习。

    >> 本章主要介绍使用3种方法提取网页中的数据,分别是正则表达式、BeautifulSoup和lxml。

    ◆ 5.1 使用正则表达式解析网页

    >> Python正则表达式的3种方法,分别是re.match、re.search和re.findall。

    >> r'(.*) are (.*? ) .*’前面的r意思是raw string,代表纯粹的字符串,使用它就不会对引号里面的反斜杠’\’进行特殊处理。

    不写r:表达式需要\\\\来匹配\

    写上r:表达式需要\\来匹配\

    >> 正则表达式如果不用r'…’方法的话,就需要进行“字符串转义”和“正则转义”

    >> 


    


    抓取博客主页所有文章标题的Python代码如下:

    
 import requests
 import re
 link = "Santos Tang"
 headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
 r = requests.get(link, headers= headers)
 html = r.text
 title_list = re.findall('

    ◆ 5.2 使用BeautifulSoup解析网页

    >> pip install bs4

    >> 使用BeautifulSoup(r.text, "lxml")将网页响应体的字符串转化为soup对象,然后就可以使用soup库的功能了。

    >> pip install lxml

    ◆ 第6章 数据存储

    >> 第6章 ◄ 数据存储 ►

    本章主要介绍将数据存储在文件中和存储在数据库中。当我们完成爬取网页并从网页中提取出数据后,需要把数据保存下来。本章将介绍两种保存数据的方法:

    (1)存储在文件中,包括TXT文件和CSV文件。

    (2)存储在数据库中,包括MySQL关系数据库和MongoDB数据库。

    ◆ 6.1 基本存储:存储至TXT或CSV

    >> [插图]

    r“”是转义字符串的特殊字符,

    \左斜杆是原始地址路径,

    \\双斜杆是转义后的路径

    /右斜杆是防止转义的路径

    >> 为了防止对反斜杠的转义,地址还可以斜杠“/”来写,也就是with open ('C:/you/desktop/title.txt', "a+") as f:。

    “\t”.join(),可以用来连接多个字符串,因为一般字符串中不会出现tab符号。

    >> output = '\t'.join(['name', 'title', 'age', 'gender'])

    f.read().spitline()

    读取文件内容,按照每一行为一个元素的列表类型返回。

    >> result = f.read().splitlines()

    >> CSV文件的每一行都用换行符分隔,列与列之间用逗号分隔。

    >> import csv
 with open('test.csv', 'r', encoding='UTF-8') as csvfile:
 csv_reader = csv.reader(csvfile)
 for row in csv_reader:
 print(row)
 print(row[0])

    >> 
 import csv
 output_list = ['1', '2', '3', '4']
 with open('test2.csv', 'a+', encoding='UTF-8', newline='') as csvfile:
 w = csv.writer(csvfile)
 w.writerow(output_list)

    ◆ 6.2 存储至MySQL数据库

    关系型数据库,表示以primary key为关联字段把各个独立的表连接起来的数据库,特点体积小、速度快而且免费,非关系型数据库就是把所有数据放在一个数据池里面,修改维护添加删除数据都很慢且难以维护。

    >> 由于MySQL关系数据库体积小、速度快而且免费,因此在网络爬虫的数据存储中作为常用的数据库。

    >> 创建数据表必须指明每一列数据的名称(column_name)和类别(column_type),正确创建数据表的方法是:

    
 CREATE TABLE urls(
 id INT NOT NULL AUTO_INCREMENT,
 url VARCHAR(1000) NOT NULL,
 content VARCHAR(4000) NOT NULL,
 created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (id)
 );

    >> pip install pymysql

    ◆ 6.3 存储至MongoDB数据库

    >> NoSQL泛指非关系型数据库。传统的SQL数据库把数据分隔到各个表中,并用关系联系起来。但是随着Web 2.0网站的兴起,大数据量、高并发环境下的MySQL扩展性差,大数据下读取,写入压力大,表结构更改困难,使得MySQL应用开发越来越复杂。相比之下,NoSQL自诞生之初就容易扩展,数据之间无关系,具有非常高的读写性能。

    >> MongoDB是一款基于分布式文件存储的数据库,本身就是为Web应用提供可扩展的高性能数据存储。因此,使用MongoDB存储网络爬虫的数据再好不过了。

    >> 使用MongoDB的程序启动方式。打开MongoDB安装文件夹,默认为C:\Program Files\MongoDB\Server\4.0 \bin,找到mongod.exe双击打开(注意有d的为启动程序)。启动程序后,再运行mongo.exe程序(没有d),如图6-29所示。

    >> pip install pymongo

    ◆ 6.4 总结

    爬虫存储数据:

    优先txt或者csv;

    如果数据量很大,打开文件都会卡顿的时候,建议使用mysql关系型数据库存储;

    如果是json格式,可以直接用mango数据库存储。

    >> 如果存储的数据不是关系型数据格式,推荐选择MongoDB,甚至可以直接存储爬取的JSON格式数据而不用进行解析。如果是关系型的表格形式,那么可以使用MySQL存储数据。

    ◆ 第7章 Scrapy框架

    >> 第7章 ◄ Scrapy框架 ►

    前面几章介绍了使用requests加BeatifulSoup工具来获取网页、解析网页、存储数据,上手比较简单,但是每个功能的代码都要自己实现。本章介绍的Scrapy是一个爬虫框架,它将上述的很多功能都封装进框架里。使用较少的代码就能完成爬虫的工作。

    本章首先介绍Scrapy和Requests的对比,然后介绍如何安装Scrapy,如何使用Scrapy进行抓取,Scrapy的注意事项,最后通过Scrapy爬虫实践来实现真正上手。

    ◆ 7.1 Scrapy是什么

    >> Scrapy是一个为了爬取网站数据,提取数据而编写的应用框架。简单来说,它把爬虫的三步:获取网页,解析网页,存储数据都整合成了这个爬虫框架。这样,通过Scrapy实现一个爬虫变得简单了很多。

    7.1.1 Scrapy架构

    下面的图7-1展示了Scrapy的架构,包括了各个组件,以及数据流的情况(箭头所示)。

    >> Scrapy是一个为了爬取网站数据,提取数据而编写的应用框架。简单来说,它把爬虫的三步:获取网页,解析网页,存储数据都整合成了这个爬虫框架。

    其实不管是爬虫还是语言的学习,都需要你先碎片化你的需求,分成每一个小步,慢慢深入,学会以后再去优化,再去借鉴别人写好的框架,你会发现眼前一亮;可是越来越熟练以后,你会发现不再喜欢条条框框,于是你又回归强撸代码。

    >> 初学者老老实实地用Requests爬取网页,用Selenium获取动态网页,用bs4解析网页,用csv存储网页;从零开始做一个爬虫项目,自己设计抓取策略会让你对爬虫有非常深入地认识。

    >> Scrapy优势在于并发性好,在做大批量数据爬虫时简单易用。

    ◆ 第8章 提升爬虫的速度

    >> 第8章 ◄ 提升爬虫的速度 ►

    通过前面7章的学习,相信读者已经能够从获取网页、解析网页、存储数据来实现一些基本的爬虫了。从本章开始,我们将进入爬虫的进阶部分,包括第8章到第13章。进阶部分的各章并没有先后顺序,对某一章感兴趣的读者可以直接跳到这章学习。

    本章将介绍如何提升爬虫的速度,主要有3种方法:多线程爬虫、多进程爬虫和多协程爬虫。相对于普通的单线程爬虫,使用这3种方法爬虫的速度能实现成倍的提升。

    展开全文
  • 常见爬虫/BOT对抗技术介绍(一)

    千次阅读 2019-01-10 17:42:46
    爬虫、反爬虫技术、反-反爬虫技术随着互联网的不断发展,也在不断发展更新, 本文简要介绍现代的爬虫/BOT对抗技术,如有疏漏,多谢指正!   一、反爬虫/BOT技术 1.1 Robots.txt Robots.txt是一个古老的爬虫协议...
  • Python爬虫常见异常及解决办法

    千次阅读 多人点赞 2020-05-12 20:44:18
    Python 的一个很重要的应用场景就是爬虫,可以高效爬取大量数据,但是在使用过程种可能会出现一些异常:cannot find Chrome binary需要通过配置参数或修改源文件实现设置binary_location参数。持续更新……
  • 它将复杂的网络请求封装为一个简单的API以供用户调用,对于一般比较简单的爬虫程序而言,requests库足矣,今天博主分享一下requests库的常见用法,本文主要针对有志爬虫的新人。 二.常见用法 2.1 安装与引用 当然,...
  • 历经 10 篇左右的 Python 字体反爬系列文章,我们又进入了一个新的主题,常见混淆...该形式代码最常见场景就是百度的统计代码,具体案例你可以寻找一下。本次我们要采集的站点是电视猫,目标地址为:。在该页面点击
  • 目前市面上我们常见爬虫软件大致可以划分为两大类:云爬虫和采集器(特别说明:自己开发的爬虫工具和爬虫框架除外) 云爬虫就是无需下载安装软件,直接在网页上创建爬虫并在网站服务器运行,享用网站提供的带宽和...
  • 主要分三大部分:用户画像常见应用场景画像产品功能技术实现方案01常见应用场景1.画像常见的应用场景不同行业业务属性不同,能采集到的数据源也不同,对画像的应用场景有不同的需求,下面梳理互联网 TOC、电商和安防...
  • 文章目录5.1 多线程爬虫5.1.1 多线程的优势5.1.2 多进程库:multiprocessing5.1.3 多线程爬虫开发5.2 爬虫常见搜索算法5.2.1 深度优先搜索5.2.2 广度优先搜索5.2.3 算法选择 5.1 多线程爬虫 5.1.1 多线程的优势 在...
  • 它是一款对目标服务器相对友好的蜘蛛程序,内置了二十余种常见或不常见的浏览器标识,能够自动处理cookie和网页来源信息,轻松绕过服务器限制,智能调整请求间隔时间,动态调整请求频率,防止对目标服务器造成干扰。...
  • 常见的反爬虫机制有哪些: • 通过use-agent识别爬虫  有些爬虫的use-agent是特殊的,与正常浏览器的不一样,可通过识别特征use-agent,直接封掉爬虫请求。 • 设置IP访问频率,如果超过一定频率,弹出验证码  ...
  • python爬虫和Java爬虫哪个更好
  • 初识爬虫——爬虫与HTML介绍

    千次阅读 多人点赞 2022-04-17 16:52:31
    程序员写代码并不是从0开始的,我们也是需要借助多个模板拼接,使得代码能够实现我们的想法,而且也并非默写出来,毕竟学习编程是开卷学习,开卷使用,加油,希望你我一同走进爬虫的世界~~
  • 场景-密码传输 前端密码传输过程中如果不加密,在日志中就可以拿到用户的明文密码,对用户安全不太负责。 这种加密其实相对比较简单,可以使用 PlanA-前端加密、后端解密后计算密码字符串的MD5/MD6存入数据库;也...
  • 应用场景不同: 企业级开发使用DES足够安全。 如果要求高使用AES。 使用DES/AES进行数据交互时要求双方都拥有相同的私钥。 三、RSA加密 RSA加密算法是一种非对称加密算法。非对称加密算法需要两个密钥,一个是公开...
  • 使用网络爬虫爬取网络数据首先需要了解网络爬虫的概念和主要分类,各类爬虫的系统结构,运作方式,常用的爬取策略,以及主要的应用场景,同时,出于版权和数据安全的考虑,还需要了解目前有关爬虫应用的合法性及爬取...
  • 最近在写一个脚手架,其中 redis 的使用场景还挺多,于是总结下它的常见使用场景 本文链接: shanyue.tech/post/redis-… github 备份: github.com/shfshanyue/… 缓存 > set User:1:name shanyue EX 100 NX OK...
  • 本文通过企业内部与互联网两个场景向大家讲书爬虫发挥了哪些重要作用。本文选自《虫术——Python绝技》一书。在大数据架构中,数据收集与数据存储占据了极为重要的地位,可以说是大数据的核心基础。而爬虫技术在这...
  • 1. 先看一个最简单的爬虫。 import requests url = "http://www.cricode.com" r = requests.get(url) print(r.text) 2. 一个正常的爬虫程序 上面那个最简单的爬虫,是一个不完整的残疾的爬虫。因为爬虫程序通常...
  • 爬虫系列之基础篇一: 初识爬虫 ...根据使用场景,网络爬虫可分为通用爬虫和聚焦爬虫两种。 通用爬虫 捜索引擎抓取系统(Baidu、Google、Yahoo等)的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互
  • Python爬虫一般会用到什么框架?哪个框架好?Python的发展让大家对它更加了解了,而且对于大型的企业来说,Python框架是非常重要的,那么Python爬虫框架有哪些?介绍为大家介绍五种常用的类型。1、Scrapy:Scrapy是一个...
  • 爬虫检测方法总结

    千次阅读 2019-07-27 11:42:26
    爬虫真是一种让人又爱又恨的存在,一方面搜索引擎的爬虫可以带来更多曝光率和更多流量,对公司是一件好事,但是也有一些个人或者竞争对手的爬虫,不但不会带来利润,反而会像DDos一样对服务器造成压力。 反爬虫一般...
  • 如果是IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能够提升...
  • 最近在写一个脚手架,其中 redis 的使用场景还挺多,于是总结下它的常见使用场景 01 缓存 > set User:1:name shanyue EX 100 NX OK > get User:1:name "shanyue" 缓存是 redis 出镜率最高的一种使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,572
精华内容 7,028
热门标签
关键字:

常见爬虫场景