No.2 从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 即可。

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

3. 设计遍历算法

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

这个算法是这样的:

  1. 初始化一个 Queue ,并放入一个作为入口的 URL,(用来存放将要被爬取的 URL )和一个 Set(存放已经爬取过的 URL , Set 是去重过的,因此我们就不用再去重了);
  2. 从Queue的队首访问一个 URL ,解析出该网页中需要的正文(前面提到的用户名)的将要被爬取链接(前面提到的,这串字符再拼上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. 先尝试获取一个网页

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

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

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

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

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

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

4. 持续改进

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

0xFF 总结

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

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


作者:dantezhao | | CSDN | GITHUB

个人主页:http://dantezhao.com
文章可以转载, 但必须以超链接形式标明文章原始出处和作者信息

你可能感兴趣的:(No.2 从0写一个爬虫,爬取500w好友关系数据)