您的位置:首页 > 编程语言 > Python开发

[Python 爬虫] 使用 Scrapy 爬取新浪微博用户信息(二) —— 编写一个基本的 Spider 爬取微博用户信息

2019-07-01 10:30 796 查看

上一篇:[Python 爬虫] 使用 Scrapy 爬取新浪微博用户信息(一) —— 新建爬虫项目

在上一篇我们新建了一个 sina_scrapy 的项目,这一节我们开始正式编写爬虫的代码。

选择目标网站

目前,新浪微博主要有三个域名,分别是:微博简化版(https://weibo.cn)微博移动端(https://m.weibo.cn)微博PC网页端(https://weibo.com/)反爬的技术也是逐渐加强。从上文我们创建 Spider 所填写的域名也可以看出,我们选用的是微博简化版(https://weibo.cn)作为爬取对象。

 

 

 

编写数据模型(Items)

我们首先明确需要获得微博用户哪些信息。我们在访问每一位用户的主页的时候 URL 上都由域名+"u"+一串数字组成,类似:https://weibo.cn/u/1809054937,而且每个用户主页URL后面那串数字都不一样,通过分析网页源码也能看到这串数字在很多关键位置都有出现,于是可以推断,这串数字就是微博用户的ID。当然,有些认证的名人主页 URL 后面跟随的不是用户ID,但是依然能从网页源码中得到用户ID,如下图:

从上图中我们能够得到的用户信息包括:用户Id、用户昵称、认证信息、简介、微博数、关注数、粉丝数等,然后我们继续点开资料,能够进一步获得更详细的信息,包括:昵称、认证、性别、地区、认证信息、简介(其他还有工作信息、教育信息等,这里不考虑)。当然,这些信息并非所有用户都有,毕竟不是每个人都会仔细填写这些资料信息的。

经过整理,我们决定爬取如下表列出的数据:

需要爬取的数据
字段名 字段类型 字段描述
user_id str 微博用户Id,微博用户的唯一标识
username str 用户昵称
webo_num int 发布的微博数量
follow_num int 用户的关注人数
fans_num int 用户的粉丝人数
gender str 用户性别
district str 地区
province str 省份
city str 城市
birthday str 生日
identify str 认证
head_img str 用户头像url
crawl_time  str 记录爬取时间

上一篇我们提到 Items 文件主要用来定义要爬取的数据模型,接下来我们就按照上面的数据字典来编写 Item,在 items 文件下编写 SinaUserItem 类,继承 scrapy.Item,代码如下:

[code]
import scrapy

class SinaUserItem(scrapy.Item):
# 微博用户唯一标识
user_id = scrapy.Field()
# 用户昵称
username = scrapy.Field()
# 微博数量
webo_num = scrapy.Field()
# 关注人数
follow_num = scrapy.Field()
# 粉丝人数
fans_num = scrapy.Field()
# 性别
gender = scrapy.Field()
# 地区
district = scrapy.Field()
# 省份
province = scrapy.Field()
# 地市
city = scrapy.Field()
# 生日
birthday = scrapy.Field()
# 简介
brief_intro = scrapy.Field()
# 认证
identify = scrapy.Field()
# 头像 URL
head_img = scrapy.Field()
# 爬取时间
crawl_time = scrapy.Field()

 

编写 Spider

在上一篇帖子中,我们在 spider 包下生成了一个爬虫应用(Spider)sina_user,代码如下。它继承了 scrapy.Spider,并为我们初始化了一些属性和方法。其中:name 是 spider 的名字,是每一个 spider 的唯一标识,allowed_domains 是一个列表类型的变量,表示爬虫允许爬取的域名范围,解析到的 request 不属于这个域名内就会被爬虫丢弃。starts_url 是爬虫开始的地址,如果不为空,第一个地址将是爬取的第一页面,也就是爬虫的入口,如果 starts_url 为空或者不填写,就必须重写父类的 start_request 方法,指定爬虫的入口。parse() 方法是爬虫的默认解析方法,用于解析 下载中间件(Downloader) 返回给 Spider 的数据。

[code]# -*- coding: utf-8 -*-
import scrapy

class SinaUserSpider(scrapy.Spider):
# 爬虫的名字,唯一标识
name = 'sina_user'
# 允许爬取的域名范围
allowed_domains = ['weibo.cn']
# 爬虫的起始页面url
start_urls = ['http://weibo.cn/']

def parse(self, response):
"""
默认解析函数
:param response:
:return:
"""
pass

我们开始编写一个最简单的爬虫,爬取 李沁 的微博信息,首先在浏览器打开 李沁 的微博,然后按 F12 调试窗口,打开页面源码,如下所示:

当我们抓取网页时,通常都需要分析网页源码,然后通过元素获取到数据,Scrapy提取数据有自己的一套机制,被称作选择器(Selector),当然,你也可以选择其他框架,例如:BeautifulSouplxml 。在这里我们采用Selector,通过右击元素,然后选择 Copy -> Copy XPath 就可以获取元素的 xpath 路径了。

在提取页面数据的时候,我们先构造一个选择器(Selector)

[code]# 构造选择器(由于在response中使用XPath、CSS查询十分普遍,因此,Scrapy提供了两个实用的快捷方式: response.xpath() 及 response.css(),不过为了学习Selector,我们还是构造一个Selector)
selector = scrapy.Selector(response)

在微博用户首页,我们能获取到的数据有:user_id、webo_num、follow_num、fans_num。分别解析这几个数据:

[code]# 解析微博用户 id
re_url = selector.xpath('//div[@class="tip2"]/a[4]/@href').re('uid=(\d{10})')
user_id = re_url[0] if re_url else ''
# 微博数
webo_num_re = selector.xpath('//div[@class="tip2"]').re(u'微博\[(\d+)\]')
webo_num = int(webo_num_re[0]) if webo_num_re else 0
# 关注人数
follow_num_re = selector.xpath('//div[@class="tip2"]').re(u'关注\[(\d+)\]')
follow_num = int(follow_num_re[0]) if follow_num_re else 0
# 粉丝人数
fans_num_re = selector.xpath('//div[@class="tip2"]').re(u'粉丝\[(\d+)\]')
fans_num = int(fans_num_re[0]) if fans_num_re else 0

另外,我们将提取的数据装载到数据模型中去,这里我们使用 Scrapy 提供的装载器(Loader)来构造数据模型。

[code]# 装载器(Loader)
load = ItemLoader(item=SinaUserItem(), response=response)

页面分析完以后,我们还不能成功访问微博页面,因为我们发送的请求没有登录的身份信息,很容易被微博服务器判定为爬虫程序,然后禁止我们访问。目前只是为了熟悉爬虫的过程,我们先从浏览器复制登录的 Cookies,然后构造 Headers,来发送请求(后续会增加 IP代理池和 Cookies池),如下图,打开调试模式 Network,任意找到一个请求,点开 Headers,复制Request Headers,如下图所示:

然后在Application-》Cookies 复制以下值到我们的代码中:

SinaUserSpider的完整代码如下(已隐去 Cookies 的值)需要注意的是,装载器(Loader)只有在最后调用 load_item() 方法时才将所有数据装载到装载器,在此之前装载器中并没有 items 的数据:

[code]# -*- coding: utf-8 -*-
import scrapy, time
from scrapy.loader import ItemLoader
from sina_scrapy.items import SinaUserItem

class SinaUserSpider(scrapy.Spider):
# 爬虫的名字,唯一标识
name = 'sina_user'
# 允许爬取的域名范围
allowed_domains = ['weibo.cn']
# 爬虫的起始页面url
start_urls = ['https://weibo.cn/u/1809054937']

def __init__(self):
self.headers = {
'Referer': 'https://weibo.cn/u/1809054937',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}

self.cookies = {
'SCF': 'xxxxxxxxxxxxx',
'SUB': 'xxxxxxxxxxxxx',
'SUHB': 'xxxxxxxxxxxxxxx',
'_T_WM': xxxxxxxxxxxxxxx
}

def start_requests(self):
"""
构造最初 request 函数\n
:return:
"""
for url in self.start_urls:
yield scrapy.Request(url=url, callback=self.base_info_parse, headers=self.headers, cookies=self.cookies)

def base_info_parse(self, response):
"""
微博用户基本信息解析函数\n
:param response:
:return:
"""
# 加载器(Loader)
load = ItemLoader(item=SinaUserItem(), response=response)
selector = scrapy.Selector(response)
# 解析微博用户 id
re_url = selector.xpath('///a[contains(@href,"uid")]/@href').re('uid=(\d{10})')
user_id = re_url[0] if re_url else ''
load.add_value('user_id', user_id)
# 微博数
webo_num_re = selector.xpath('//div[@class="tip2"]').re(u'微博\[(\d+)\]')
webo_num = int(webo_num_re[0]) if webo_num_re else 0
load.add_value('webo_num', webo_num)
# 关注人数
follow_num_re = selector.xpath('//div[@class="tip2"]').re(u'关注\[(\d+)\]')
follow_num = int(follow_num_re[0]) if follow_num_re else 0
load.add_value('follow_num', follow_num)
# 粉丝人数
fans_num_re = selector.xpath('//div[@class="tip2"]').re(u'粉丝\[(\d+)\]')
fans_num = int(fans_num_re[0]) if fans_num_re else 0
load.add_value('fans_num', fans_num)
# 记录爬取时间
load.add_value('crawl_time', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
return load.load_item()

我们打开编译器的 Console,进入到 sina_scrapy 目录下,执行以下命令,启动爬虫:

[code]scrapy crawl sina_user

运行结果如下:

往下翻,能够看到这样一行信息:被 rebots.txt 禁止。 rebots.txt 是一种网络爬虫排除标准,但并不是强制的,类似于服务器与爬虫程序之间的一种“君子协定”。

[code]2019-07-01 17:42:20 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET https://weibo.cn/u/1809054937>

我们只需要在 settings 文件里面关闭这个设置就行了:

[code]# 是否遵循网络爬虫排除标准
ROBOTSTXT_OBEY = False

然后我们再次运行爬虫程序,就可以看到输出我们爬取的信息:

[code]2019-07-01 17:52:56 [scrapy.core.scraper] DEBUG: Scraped from <200 https://weibo.cn/u/1809054937>
{'crawl_time': ['2019-07-01 17:52:56'],
'fans_num': [20714189],
'follow_num': [326],
'user_id': ['1809054937'],
'webo_num': [2515]}

至此,我们已经成功编写了一个简单的爬虫应用了!

 

总结

在这一篇博客中,主要介绍了如何编写一个 Scrapy 的爬虫应用,以及 Scrapy 用到的基本技术,下一篇将扩展爬取的信息,并添加分页的爬取以及介绍如何编写 item pipline 将爬取到的数据保存到 MongoDB 中。

 

下一篇:[Python 爬虫] 使用 Scrapy 爬取新浪微博用户信息(三) —— 数据的持久化——使用MongoDB存储爬取的数据

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐