“入门”是良好的动机,但是可能作用缓慢。如果你手里或者脑子里有一个项目,那么实践起来你会被目标驱动,而不会像学习模块一样慢慢学习。

另外如果说知识体系里的每一个知识点是图里的点,依赖关系是边的话,那么这个图一定不是一个有向无环图。因为学习A的经验可以帮助你学习B。因此,你不需要学习怎么样“入门”,因为这样的“入门”点根本不存在!你需要学习的是怎么样做一个比较大的东西,在这个过程中,你会很快地学会需要学会的东西的。当然,你可以争论说需要先懂Python,不然怎么学会Python做爬虫呢?但是事实上,你完全可以在做这个爬虫的过程中学习Python的

看到前面很多答案都讲的“术”——用什么软件怎么爬,那我就讲讲“道”和“术”吧——爬虫怎么工作以及怎么在Python实现。

对Python感兴趣的小伙伴,记得私信小编“007”领取全套Python资料哦。

先长话短说summarize一下,你需要学习:

  1. 基本的爬虫工作原理
  2. 基本的http抓取工具,scrapy
  3. Bloom Filter
  4. 链接:https://llimllib.github.io/bloomfilter-tutorial/
  5. 如果需要大规模网页抓取,你需要学习分布式爬虫的概念。其实没那么玄乎,你只要学会怎样维护一个所有集群机器能够有效分享的分布式队列就好。最简单的实现是python-rq
  6. 链接:https://github.com/nvie/rq
  7. rq和Scrapy的结合:darkrho/scrapy-redis
  8. 链接:https://github.com/rmax/scrapy-redis
  9. 后续处理,网页析取grangier/python-goose,存储(Mongodb)
  10. 链接:https://github.com/grangier/python-goose

以下是短话长说:

说说当初写的一个集群爬下整个豆瓣的经验吧。

1)首先你要明白爬虫怎样工作

想象你是一只蜘蛛,现在你被放到了互联“网”上。那么,你需要把所有的网页都看一遍。怎么办呢?没问题呀,你就随便从某个地方开始,比如说人民日报的首页,这个叫initial pages,用$表示吧。

在人民日报的首页,你看到那个页面引向的各种链接。于是你很开心地从爬到了“国内新闻”那个页面。太好了,这样你就已经爬完了俩页面(首页和国内新闻)!暂且不用管爬下来的页面怎么处理的,你就想象你把这个页面完完整整抄成了个html放到了你身上。

突然你发现, 在国内新闻这个页面上,有一个链接链回“首页”。作为一只聪明的蜘蛛,你肯定知道你不用爬回去的吧,因为你已经看过了啊。所以,你需要用你的脑子,存下你已经看过的页面地址。这样,每次看到一个可能需要爬的新链接,你就先查查你脑子里是不是已经去过这个页面地址。如果去过,那就别去了。

好的,理论上如果所有的页面可以从initial page达到的话,那么可以证明你一定可以爬完所有的网页。

那么在Python里怎么实现呢?很简单

import Queueinitial_page = "http://www.renminribao.com"url_queue = Queue.Queue()seen = set()seen.insert(initial_page)url_queue.put(initial_page)#一直进行直到海枯石烂while(True):  if url_queue.size()>0: #拿出队例中第一个的url current_url = url_queue.get() #把这个url代表的网页存储好  store(current_url)  #提取把这个url里链向的url  for next_url in extract_urls(current_url):  if next_url not in seen:  seen.put(next_url) url_queue.put(next_url) else: break

写得已经很伪代码了。

所有的爬虫的backbone都在这里,下面分析一下为什么爬虫事实上是个非常复杂的东西——搜索引擎公司通常有一整个团队来维护和开发。

2)效率

如果你直接加工一下上面的代码直接运行的话,你需要一整年才能爬下整个豆瓣的内容。更别说Google这样的搜索引擎需要爬下全网的内容了。

问题出在哪呢?需要爬的网页实在太多太多了,而上面的代码太慢太慢了。设想全网有N个网站,那么分析一下判重的复杂度就是N*log(N),因为所有网页要遍历一次,而每次判重用set的话需要log(N)的复杂度。OK,OK,我知道Python的set实现是hash——不过这样还是太慢了,至少内存使用效率不高。

通常的判重做法是怎样呢?Bloom Filter. 简单讲它仍然是一种hash的方法,但是它的特点是,它可以使用固定的内存(不随url的数量而增长)以O(1)的效率判定url是否已经在set中。可惜天下没有白吃的午餐,它的唯一问题在于,如果这个url不在set中,BF可以100%确定这个url没有看过。但是如果这个url在set中,它会告诉你:这个url应该已经出现过,不过我有2%的不确定性。注意这里的不确定性在你分配的内存足够大的时候,可以变得很小很少。一个简单的教程:Bloom Filters by Example。

注意到这个特点,url如果被看过,那么可能以小概率重复看一看(没关系,多看看不会累死)。但是如果没被看过,一定会被看一下(这个很重要,不然我们就要漏掉一些网页了!)。

好,现在已经接近处理判重最快的方法了。另外一个瓶颈——你只有一台机器。不管你的带宽有多大,只要你的机器下载网页的速度是瓶颈的话,那么你只有加快这个速度。用一台机子不够的话——用很多台吧!当然,我们假设每台机子都已经进了最大的效率——使用多线程(Python的话,多进程吧)。

3)集群化抓取

爬取豆瓣的时候,我总共用了100多台机器昼夜不停地运行了一个月。想象如果只用一台机子你就得运行100个月了…

那么,假设你现在有100台机器可以用,怎么用Python实现一个分布式的爬取算法呢?

我们把这100台中的99台运算能力较小的机器叫作slave,另外一台较大的机器叫作master,那么回顾上面代码中的url_queue,如果我们能把这个queue放到这台master机器上,所有的slave都可以通过网络跟master联通,每当一个slave完成下载一个网页,就向master请求一个新的网页来抓取。而每次slave新抓到一个网页,就把这个网页上所有的链接送到master的queue里去。同样,bloom filter也放到master上,但是现在master只发送确定没有被访问过的url给slave。Bloom Filter放到master的内存里,而被访问过的url放到运行在master上的Redis里,这样保证所有操作都是O(1)。(至少平摊是O(1),Redis的访问效率见:https://redis.io/commands/linsert)

考虑如何用Python实现:

在各台slave上装好scrapy,那么各台机子就变成了一台有抓取能力的slave,在master上装好Redis和rq用作分布式队列。

代码于是写成

#slave.pycurrent_url = request_from_master()to_send = []for next_url in extract_urls(current_url): to_send.append(next_url)store(current_url);send_to_master(to_send)#master.pydistributed_queue = DistributedQueue()bf = BloomFilter()initial_pages = "www.renmingribao.com"while(True): if request == 'GET': if distributed_queue.size()>0: send(distributed_queue.get()) else: break elif request == 'POST': bf.put(request.url)

好的,其实你能想到,有人已经给你写好了你需要的:darkrho/scrapy-redis · GitHub

4)展望及后处理

虽然上面用很多“简单”,但是真正要实现一个商业规模可用的爬虫并不是一件容易的事。上面的代码用来爬一个整体的网站几乎没有太大的问题。

但是如果附加上你需要这些后续处理,比如

  1. 有效地存储(数据库应该怎样安排)
  2. 有效地判重(这里指网页判重,咱可不想把人民日报和抄袭它的大民日报都爬一遍)
  3. 有效地信息抽取(比如怎么样抽取出网页上所有的地址抽取出来,“朝阳区奋进路中华道”),搜索引擎通常不需要存储所有的信息,比如图片我存来干嘛…
  4. 及时更新(预测这个网页多久会更新一次)

如你所想,这里每一个点都可以供很多研究者十数年的研究。虽然如此,“路漫漫其修远兮,吾将上下而求索”。

爬虫python入门_如何入门Python爬虫?爬虫原理及过程详解相关推荐

  1. python中exchange函数使用_python基于exchange函数发送邮件过程详解

    python基于exchange函数发送邮件过程详解 作者: shuzihua 更新时间:2020-11-06 10:40:35 原文链接 1.Python hasattr() 函数 描述 hasat ...

  2. python 运算太慢怎么办_干货|如何入门 Python 爬虫?爬虫原理及过程详解

    点击蓝字"python教程"关注我们哟! 前言 Python现在非常火,语法简单而且功能强大,很多同学都想学Python!所以小的给各位看官们准备了高价值Python学习视频教程及 ...

  3. python爬虫原理-干货|如何入门 Python 爬虫?爬虫原理及过程详解

    前言 Python现在非常火,语法简单而且功能强大,很多同学都想学Python!所以小的给各位看官们准备了高价值Python学习视频教程及相关电子版书籍,欢迎前来领取! "入门"是 ...

  4. python爬虫教程:基于python框架Scrapy爬取自己的博客内容过程详解

    前言 python中常用的写爬虫的库常有urllib2.requests,对于大多数比较简单的场景或者以学习为目的,可以用这两个库实现.这里有一篇我之前写过的用urllib2+BeautifulSou ...

  5. python读取yaml文件的内容_Python读取YAML文件过程详解

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  6. python 切换环境_python多环境切换及pyenv使用过程详解

    curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 下载如下报错,则安装nss ...

  7. Java爬虫:大量抓取二手房信息并存入云端数据库过程详解(三)

    这里详细讲一下将解析好的所有房源数据存入云端数据库的表中: 1.首先是获得数据库连接,Java提供了数据库链接的接口,但实现是由各个数据库提供者自己实现的,这里需要mysql提供的第三方包:mysql ...

  8. opencv python考勤_Python基于Opencv来快速实现人脸识别过程详解(完整版)

    前言 随着人工智能的日益火热,计算机视觉领域发展迅速,尤其在人脸识别或物体检测方向更为广泛,今天就为大家带来最基础的人脸识别基础,从一个个函数开始走进这个奥妙的世界. 首先看一下本实验需要的数据集,为 ...

  9. 检查虚ip跟实ip之间网络问题_虚电路有哪些特点 虚电路原理介绍【详解】

    虚电路,虚电路的特点,虚电路的原理是什么? 虚电路是交换网络(ATM.帧中继.IP或因特网)上两个终端站之间的点对点通信链路.虚电路的设计是在交换网络上仿真物理电路的特性.家中与电话公司中心局之间的模 ...

最新文章

  1. 大型分布式网站术语分析 15 条,你知道几条?
  2. gradle构建脚本、依赖、插件管理、生命周期进阶教程
  3. 简单而又不平凡的杨辉三角形
  4. 计算机原理及应用课程,课程介绍
  5. div靠边隐藏_css如何隐藏div不占位置?
  6. [数位DP]JZOJ 3363 Number
  7. 软件测试python测试步骤_软件测试员必备基础:3分钟带你入门自动化测试!
  8. jquery 分片上传php,jquery 大文件分片上传插件 fcup.js
  9. Android Sensor传感器系统架构初探
  10. 自己动手写操作系统——开发环境搭建
  11. 机器视觉运动控制一体机应用例程|芯片引脚缺陷检测系统
  12. mysql 词频分析_09 使用python完成词频统计
  13. wlan和wifi的区别
  14. 数据结构c语言版陈越,数据结构 陈越
  15. 保护眼睛颜色的RGB
  16. 2022秋招前端面试题(一)(附答案)
  17. 排序算法之插入排序法
  18. 高中计算机奥林匹克竞赛试题及答案,答案来了!2020年第36届全国高中数学奥赛决赛完整试题和参考答案...
  19. simulia助力,柔性屏时代即将到来
  20. 通达信 数据格式 java_通达信日线 数据格式

热门文章

  1. 精选素材模板丨极简风简历模板
  2. 移动端APP扁平化UI设计解析
  3. android中activity布局,Android中登录布局展示Activity
  4. javamail 超时_为什么JavaMail连接超时太长
  5. Ubuntu16.04下禁用scp、sftp和winscp
  6. void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
  7. OpenCV的基本数据结构
  8. python按照每行输出八个_Python/PyCharm的每行输出
  9. 傅里叶变换@(stft和istft)
  10. scala的运算符(四)