当前位置:   article > 正文

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

爬取新浪微博内容及用户信息

上一篇:[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_idstr微博用户Id,微博用户的唯一标识
usernamestr用户昵称
webo_numint发布的微博数量
follow_numint用户的关注人数
fans_numint用户的粉丝人数
genderstr用户性别
districtstr地区
provincestr省份
citystr城市
birthdaystr生日
identifystr认证
head_imgstr用户头像url
crawl_time str记录爬取时间

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

  1. import scrapy
  2. class SinaUserItem(scrapy.Item):
  3. # 微博用户唯一标识
  4. user_id = scrapy.Field()
  5. # 用户昵称
  6. username = scrapy.Field()
  7. # 微博数量
  8. webo_num = scrapy.Field()
  9. # 关注人数
  10. follow_num = scrapy.Field()
  11. # 粉丝人数
  12. fans_num = scrapy.Field()
  13. # 性别
  14. gender = scrapy.Field()
  15. # 地区
  16. district = scrapy.Field()
  17. # 省份
  18. province = scrapy.Field()
  19. # 地市
  20. city = scrapy.Field()
  21. # 生日
  22. birthday = scrapy.Field()
  23. # 简介
  24. brief_intro = scrapy.Field()
  25. # 认证
  26. identify = scrapy.Field()
  27. # 头像 URL
  28. head_img = scrapy.Field()
  29. # 爬取时间
  30. 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 的数据。

  1. # -*- coding: utf-8 -*-
  2. import scrapy
  3. class SinaUserSpider(scrapy.Spider):
  4. # 爬虫的名字,唯一标识
  5. name = 'sina_user'
  6. # 允许爬取的域名范围
  7. allowed_domains = ['weibo.cn']
  8. # 爬虫的起始页面url
  9. start_urls = ['http://weibo.cn/']
  10. def parse(self, response):
  11. """
  12. 默认解析函数
  13. :param response:
  14. :return:
  15. """
  16. pass

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

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

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

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

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

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

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

  1. # 装载器(Loader)
  2. load = ItemLoader(item=SinaUserItem(), response=response)

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

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

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

  1. # -*- coding: utf-8 -*-
  2. import scrapy, time
  3. from scrapy.loader import ItemLoader
  4. from sina_scrapy.items import SinaUserItem
  5. class SinaUserSpider(scrapy.Spider):
  6. # 爬虫的名字,唯一标识
  7. name = 'sina_user'
  8. # 允许爬取的域名范围
  9. allowed_domains = ['weibo.cn']
  10. # 爬虫的起始页面url
  11. start_urls = ['https://weibo.cn/u/1809054937']
  12. def __init__(self):
  13. self.headers = {
  14. 'Referer': 'https://weibo.cn/u/1809054937',
  15. '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'
  16. }
  17. self.cookies = {
  18. 'SCF': 'xxxxxxxxxxxxx',
  19. 'SUB': 'xxxxxxxxxxxxx',
  20. 'SUHB': 'xxxxxxxxxxxxxxx',
  21. '_T_WM': xxxxxxxxxxxxxxx
  22. }
  23. def start_requests(self):
  24. """
  25. 构造最初 request 函数\n
  26. :return:
  27. """
  28. for url in self.start_urls:
  29. yield scrapy.Request(url=url, callback=self.base_info_parse, headers=self.headers, cookies=self.cookies)
  30. def base_info_parse(self, response):
  31. """
  32. 微博用户基本信息解析函数\n
  33. :param response:
  34. :return:
  35. """
  36. # 加载器(Loader)
  37. load = ItemLoader(item=SinaUserItem(), response=response)
  38. selector = scrapy.Selector(response)
  39. # 解析微博用户 id
  40. re_url = selector.xpath('///a[contains(@href,"uid")]/@href').re('uid=(\d{10})')
  41. user_id = re_url[0] if re_url else ''
  42. load.add_value('user_id', user_id)
  43. # 微博数
  44. webo_num_re = selector.xpath('//div[@class="tip2"]').re(u'微博\[(\d+)\]')
  45. webo_num = int(webo_num_re[0]) if webo_num_re else 0
  46. load.add_value('webo_num', webo_num)
  47. # 关注人数
  48. follow_num_re = selector.xpath('//div[@class="tip2"]').re(u'关注\[(\d+)\]')
  49. follow_num = int(follow_num_re[0]) if follow_num_re else 0
  50. load.add_value('follow_num', follow_num)
  51. # 粉丝人数
  52. fans_num_re = selector.xpath('//div[@class="tip2"]').re(u'粉丝\[(\d+)\]')
  53. fans_num = int(fans_num_re[0]) if fans_num_re else 0
  54. load.add_value('fans_num', fans_num)
  55. # 记录爬取时间
  56. load.add_value('crawl_time', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
  57. return load.load_item()

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

scrapy crawl sina_user

运行结果如下:

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

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

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

  1. # 是否遵循网络爬虫排除标准
  2. ROBOTSTXT_OBEY = False

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

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

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

 

总结

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

 

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56872
推荐阅读
相关标签
  

闽ICP备14008679号