从0写一个爬虫,爬取500w好友关系数据

0x00 前言

上一篇文章已经写了一部分数据获取和爬虫的内容,这篇文章我们一起来实现一个网络爬虫,用这个小爬虫来爬取500w的简书的粉丝关系对。

1. 两个小问题

为什么要爬关系对数据呢,爬些文字数据岂不更好?

为什么要爬关系对数据?因为居士最近正在搞和社交关系相关的项目,需要对大量的关系数据做处理,而且要用到 LPA 、 PageRank 这些算法,写博客本来就需要为自己学习和工作来服务,为了加深自己的理解,因此前几篇博客都和关系数据相关。后续当需要文本数据的时候,会有专门的文章。

为什么要爬简书数据呢?

为什么爬简书的数据?这就和我们爬虫的实现有关了,比较成熟的网站都有很强的防爬虫措施,比如xx百科,很容易被封IP。但是像简书和CxxN这些网站的防爬虫相对做的比较弱,比较容易下手。

2. 通过本文能收获什么?

  1. 你将能了解到如何针对特定网站也设计一个爬虫,设计思路很重要。我们会主要来讲怎么设计,实现的代码很简单,大致过一下,不一行行讲了,都有详细注释。
  2. 你会了解到爬虫的几个工程要点和一种简单的实现方法:图的BFS,页面的解析和已爬取URL列表的维护。
  3. 完整能运行的代码,有需要的话爬好的数据也可以拿走。

0x01 设计一个小爬虫

1. 明确目标

先明确一下目标:我们要爬取简书中的的关注数据,比如A关注B,那我们就存下来B A这样一条数据,即人+粉丝,以Tab分割。

2. 总结规则

下图,是我们想要爬取数据的主要页面,我们希望从这个页面得到这样一份数据:

dantezhao   小飞_b7ef
dantezhao   Daisy向阳花儿
dantezhao   Maxine24w
dantezhao   Jialin28

接着,我们需要看一下它返回给浏览器的 HTML 的source code什么样子,然后从中来解析出来这个关系对。在Chrome中直接在当前网页下按 ctrl+u 即可。

从下图中,我们可以看到,只要拿到红框圈住的部分就可以了。仔细看一下,红框圈住的部分包含两块内容:<a class="name" href="/u/9e2b3667983d">用户名。 这两块内容我们都需要,特别是前面的那串奇怪的字符,属于上一篇文章《No.1 聊一聊数据获取和爬虫》中提到的URL解析。能把这个解析出来,我们就能不停地获取新的网页链接,爬取内容。

3. 设计遍历算法

这里我们会用到图的广度有限遍历,我们会有一个十分简单的实现版本,简单,但是够用。

这个算法是这样的:

  1. 初始化一个 Queue ,并放入一个作为入口的 URL,(用来存放将要被爬取的 URL )和一个 Set(存放已经爬取过的 URL , Set 是去重过的,因此我们就不用再去重了);
  2. 从Queue的队首访问一个 URL ,解析出该网页中需要的正文(前面提到的用户名)的将要被爬取链接(前面提到的<a class="name" href="/u/9e2b3667983d">,这串字符再拼上www.jianshu.com/即代表一个新的URL);
  3. 将该 URL 从 Queue 的队首移除并放入 Set 中,并将在该 URL 中解析出来的新的 URL 放入 Queue 的队尾。
  4. 跳转到第二步继续执行。

好了,遍历大致就是这样实现了,会额外用到一个队列和一个集合。

4. 程序整体框架

然后我们看一下程序的整体框架(在医院等人的时候画的,本居士也是够拼了)。

这里不再细致讲框架的内容了,仔细看一下图中的元素即可。

5. 其它

我们的爬虫的算法和程序大致框架都已经有了,整体骨骼已有,再需要补充几点就可以来实现了。

关系对的表示

我们在存放关系对的时候使用简书生成的一个唯一的userid,而不是用户名。

因为通过这个字符串能唯一标识一个用户,而且这个字符串还能拼接成新的URL,也就是说解析出来了这个9e2b3667983d,既能当作关系,也可以当作新的URL一部分。

URL解析

通过HTML的标签来解析出下面图中的1,再拼上http://www.jianshu.com/users/,最后得到一个新的新的URLhttp://www.jianshu.com/users/2453cf172ab4

粉丝和关注

粉丝和关注分别在两个页面,他们的网页的前半部分是相同的:http://www.jianshu.com/users/2453cf172ab4,不同的地方在于一个是followers一个是following

另外这里还设计到简书的分页问题,根据观察,我们可以发现是每页有9个用户,每一页需要加一个?page=N。也就是说一个完整的网页应该是这个样子:http://www.jianshu.com/users/2453cf172ab4/following?page=2

数据持久化

最终的数据都会存在本地磁盘,这里不再用数据库,比较重。

0x02 实现

实现这一块本来是想详细的写的,不过大部分的精力都在设计上了,实现这一块就少写一点,不大段贴代码了。

整个程序的框架在前面已有提到,可以往上翻看一下图,下面主要讲一下各个模块的实现。

1. 用到的 Python 包

  • Python版本:3.5
  • BeautifulSoup:解析HTML标签
  • urllib:获取URL的内容

2. BFS的实现

看代码,大致的思路其实很简单。

3. 页面的获取

最简单的页面获取程序非常短,三行就可以搞定。下面这三行代码,拿去运行一下,就可以把一个网页的正文全部抓下来。

import urllib.request
data = urllib.request.urlopen("http://blog.csdn.net/zhaodedong").read().decode('UTF-8')
print (data)

我们在此基础上还要再做页面的解析,不然存下来也没用,这里面就用到了BeautifulSoup,专门来解析HTML,这里不再详细说明,感兴趣的同学,搜一下官网,很容易。

# 根据url获取一页的所有用户
def get_user_set(url):
	data = urllib.request.urlopen(url).read()
	data = data.decode('UTF-8')
	soup = BeautifulSoup(data, 'html.parser')
	links = soup.find_all("a", class_="name")
	user_set=set()
	for link in links:
		user = link.get("href").split("/")[2].strip()
		if (len(user) > 1):
			user_set.add(user)
	return user_set

4. 文件持久化

为了避免频繁在磁盘读写文件,该程序是每抓取五个用户的所有关系对后写一次文件,一个用户平均有500个关系对,也就是说,平均2500个关系对写一次文件。写文件的逻辑很简单,可以看一下代码。

另外我们的已访问URL列表也是存在本地文件中,方便多次运行程序重复爬网页。

5. 防爬虫

我们写的爬虫相对来讲算是很暴力的,一般都会被各个网站屏蔽,比如:ip限制、Http请求的Header限制。

这里我们为了防止简书干掉我们的小爬虫,需要加两个操作:

  1. 每次请求页面,随机获取一个Header。
  2. 每次请求页面,随机休息1~3秒。

经过这两步优化,基本上可以运行很长时间了,如果还是被封掉,就可以考虑使用代理和分布式爬虫了。因为爬简书封IP,而且自己不是特别继续这个数据,就用单进程来写了,跑几天就能爬下500w的数据。

0x03 零基础学爬虫的建议

目前这个小爬虫已经运行了三四天了,总共爬取了500w左右的关系对。最后的关系对数据长下面这个样子。

看文章其实只能帮助理解,爬虫这东西,还是要跑一下代码,运行两次就能搞定了。

这里推荐一下零基础的同学学习Python爬虫的顺序。

1. 先尝试获取一个网页

先用下面代码就可以获取一个网页,打印出来看一下

123

import urllib.requestdata = urllib.request.urlopen("http://blog.csdn.net/zhaodedong").read().decode('UTF-8')print (data)

2. 获取网页中自己关心的内容

获取到了HMTL的全部内容后,就要来对它进行解析,建议尝试一下BeautifulSoup,运行一下官方的demo,上手绝对快。

3. 接着让爬虫不停歇地跑下去

然后就是爬虫的广度优先遍历了,本文和上一篇文章都有提到,而且也有实现,可以参照一下。 或者是直接运行现有的例子就可以。

4. 持续改进

只要爬虫能跑起来之后就好办了,遇到问题了就解决。比如说遇到防爬虫了,我们就想办法来骗它们;爬得慢了我们就改成多线程的,还不行就改成分布式的。遇到问题了解决就行。

0xFF 总结

文章是在医院等人的时候写的,思路被打断好多次,因此有一点不是特别流畅的地方,不过我想大致的内容还是表达出来了。特别是思路方面,先了解了思路,实现起来还是挺简单的,一两个小时就可以写出来。

现在已经爬了500w左右的关系对数据,也在此基础上了玩了玩PageRank和社区划分的算法,也实现了相应MapReduce版本的算法,后面会一点点地写出来。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小特工作室

工作流组件示例(全部开源)

1.概述 1.1简介 本文档旨在帮助开发人员快速使用工作流组件,完成OA或审批等涉及到工作流组件的系统开发工作 1.2组件构成 1.2.1组件层次图 ? 组...

72110
来自专栏农夫安全

浅说驱动程序的加载过程

在开始之前,首先简要介绍一下本文的主题,这篇文章是关于将内核模块加载到操作系统内核的方法的介绍。所谓“内核模块”,指的便是通常所说的驱动程序。不过因为加载到内核...

3399
来自专栏小巫技术博客

推荐:Mac下高效静态代码分析神器Unstand详解

1051
来自专栏PPV课数据科学社区

[实用]手把手教你用python抓网页数据

前言: 数据科学越来越火了,网页是数据很大的一个来源。最近很多人问怎么抓网页数据,据我所知,常见的编程语言(C++,java,python)都可以实现抓网页数据...

4515
来自专栏Albert陈凯

手把手教你用python抓取网页导入模块 urllib2随便查询一篇文章,比如On random graph。对每一个查询googlescholar都有一个url,这个url形成的规则是要自己分析的。

http://www.1point3acres.com/bbs/thread-83337-1-1.html **前言: ** 数据科学越来越火了,网页是数据...

3137
来自专栏FreeBuf

对自助提卡系统的一次代码审计

并非有意愿要审计该站,前面的走的黑盒没有过于精彩部分就不在贴上了,对于此系统站你们懂的,多说无益,这套程序是开源的,像这种自助提卡系统相信大家已经不在陌生了,很...

1793
来自专栏美团技术团队

Android动态日志系统Holmes

背景 美团点评公司是全球领先的一站式生活服务平台,为6亿多消费者和超过450万优质商户提供连接线上线下的电子商务网络。美团点评的业务覆盖了超过200个丰富品类和...

64310
来自专栏Java Web

Java学习笔记(4)——并发基础

前言 当我们使用计算机时,可以同时做许多事情,例如一边打游戏一边听音乐。这是因为操作系统支持并发任务,从而使得这些工作得以同时进行。 那么提出一个问题:如果我...

3113
来自专栏FreeBuf

滥用Edge浏览器的“恶意站点警告”特性,实现地址栏欺骗

前言 在过去的几个月里,我们看到使用这种以技术支撑的骗术日益增多,用户的浏览器会被辣眼睛的红屏以及类似”你的电脑可能存在风险”的提示消息”锁定”。当然,这种情形...

2309
来自专栏進无尽的文章

多线程-概述及底层实现机制浅析

在打算写这篇多线层底层实现机制的时候,突然发现自己对于计算机竟然懂得这么表面,对于CPU的工作原理都不完全清楚,于是又转头查看了一些CPU相关的资料。也不敢钻的...

1421

扫码关注云+社区

领取腾讯云代金券