首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从0写一个爬虫,爬取500w好友关系数据

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

作者头像
木东居士
发布2018-05-25 15:52:44
1.5K0
发布2018-05-25 15:52:44
举报

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版本的算法,后面会一点点地写出来。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 前言
    • 1. 两个小问题
      • 为什么要爬关系对数据呢,爬些文字数据岂不更好?
      • 为什么要爬简书数据呢?
    • 2. 通过本文能收获什么?
    • 0x01 设计一个小爬虫
      • 1. 明确目标
        • 2. 总结规则
          • 3. 设计遍历算法
            • 4. 程序整体框架
              • 5. 其它
                • 关系对的表示
                • URL解析
                • 粉丝和关注
                • 数据持久化
            • 0x02 实现
              • 1. 用到的 Python 包
                • 2. BFS的实现
                  • 3. 页面的获取
                    • 4. 文件持久化
                      • 5. 防爬虫
                      • 0x03 零基础学爬虫的建议
                        • 1. 先尝试获取一个网页
                          • 2. 获取网页中自己关心的内容
                            • 3. 接着让爬虫不停歇地跑下去
                              • 4. 持续改进
                              • 0xFF 总结
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档