最近阅读了崔庆才写的《Python3网络爬虫开发实战》,系统地学习一下利用Python写网络爬虫。由于这本书出版时间是2018年,很多书中案例涉及的网站已经改版,基本上每个案例都需要自己再研究一下网站改版后新的结构来爬取数据。这篇博文就来介绍一下如何爬取一下新浪微博用户的微博信息和下载该用户的微博图片,其中涉及到的技术包括Ajax数据爬取,Python和MongoDB的交互以及windows下python的多进程编程。

使用Ajax请求爬取用户微博信息并存储到后端MongoDB

关于基础的网页前端各个节点的结构,http的get和post请求,requests库中的get函数用法,普通网页header请求头的构建,Beautiful Soup和pyquery解析库的使用这里不做过多介绍,对这方面不是很了解的同学建议先去看一下《Python3网络爬虫开发实战》中的前四章来详细了解一下。这里简要介绍一下什么是Ajax加载,它是一种异步的数据加载方式,原始的页面最初不会包含某些数据,原始页面加载完之后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现到网页上,这其实就是发送了一个Ajax请求,本质上来讲Ajax是利用了JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。
以我的移动端新浪微博页面为例:https://m.weibo.cn/u/6163257669,选择Network下面的XHR选项卡,点击刷新页面之后,在下拉的过程中会发现有getIndex?开头的请求冒出来,这就是Ajax请求,构造Ajax请求主要是提供Requests header和Query String Parameters中的参数。

再看一下该请求返回的数据Previews,如下图所示,其中cards中的绝大部分card对应的是每条微博,点开一个card,若有mblog字段代表这条card对应的是一条微博,mblog字段下面不同字段包含这条微博的所有信息。我们这次主要是爬取每条微博的id,text,attitudes,comments,reposts这几个属性。然后将信息写入MongoDB中,windows下MongoDB的安装可以参考https://www.runoob.com/mongodb/mongodb-window-install.html,为了能够之直接在命令行通过mongo命令启动数据库命令行,可以将mongo安装目录(例如C:\Program Files\MongoDB\Server\4.2\bin)添加到相应的系统环境变量。

关于构造请求的query string parameters参数,其中有一个since_id,这个代表每次Ajax加载时对应的第一条微博id,我们遍历所有微博的方法就是从该用户第一条微博id(有些用户页面上的第一条微博是置顶的,注意不要选该微博作为第一条微博,需要找时间上最晚发的微博)开始作为起始的since_id,返回的数据包含之后的十条card,然后再以最后一个card作为起始的since_id再爬取后续的十条card(下一次返回的结果中要去掉第一条,防止重复爬取该条微博),以此类推最终遍历完所有微博。最终爬取的脚本如下所示:

#author:xfxy
#time:2020/04/18from urllib.parse import urlencode
from pyquery import PyQuery as pq
import requests
import time
import pymongo
base_url='https://m.weibo.cn/api/container/getIndex?'
def get_all_weibo(since_id):    #该函数通过提供since_id参数来爬取cardsif since_id==None:return None#请求头的构建headers={'Referer': 'https://m.weibo.cn/u/6163257669?from=myfollow_all&is_all=1&sudaref=login.sina.com.cn','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.4040.400','X-Requested-With': 'XMLHttpRequest',}#Query string parameters的构建params={'from': 'myfollow_all','is_all': '1','sudaref': 'login.sina.com.cn','type': 'uid','value': '6163257669', #这是我微博的id,如果想爬取某个用户的微博,需要更改value,containerid,headers中的Referer'containerid': '1076036163257669','since_id': since_id,}url=base_url+urlencode(params) #通过Query string parameters构造请求urlr=requests.get(url,headers=headers)return r.json().get('data').get('cards')items=get_all_weibo('4494845651530130') #since_id为我第一条微博的id
client = pymongo.MongoClient(host='localhost',port=27017) #建立和MongoDB的链接
db=client.weibo #建立数据库weibo
collection=db.xfxy #建立键值对集合collections
while(1): #循环退出条件写在循环体中for item in items:if item.get('mblog')!=None:item=item.get('mblog')else:continueweibo=dict()weibo['id']=item.get('id')weibo['text']=pq(item.get('text')).text()weibo['attitudes']=item.get('attitudes_count')weibo['comments']=item.get('comments_count')weibo['reposts']=item.get('reposts_count')print(weibo)collection.insert(weibo) #向MongoDB中插入数据for i in range(len(items)):  #寻找最后一条含有mblog字段的card,取其mblog字段中的id作为下一次循环的idif items[len(items)-1-i].get('mblog')!=None:since_id=items[-1].get('mblog').get('id')breakitems=get_all_weibo(since_id)time.sleep(0.5) #设置sleep防止请求过于频繁if items==None or items[0]==items[-1]: #循环退出条件,只剩最后一条card或者不存在cardbreakitems=items[1:] #去掉作为请求的since_id对应的微博,防止重复爬取

最后print出的结果和存储在MongoDB中的数据如下所示:

Windows下多进程爬取微博用户高清大图

有些时候我们关注了一些喜欢发高清美图的博主,想要爬取该博主发的原创微博的原图。原创微博带有图片的,mblog字段中会有pics字段,如下图所示中最后那行的pics,点开后我们可以看到该条微博内每张图片都单独列了一个条目,如图中的0,0下面large字段字段内的url就是对应的大图的网址,通过get该网址的内容便可下载该图片。


我们首先用单进程的方法爬取微博用户发的大图,脚本如下所示,遍历微博和之前的脚本使用的方法相同,不同的地方在于图片下载url的获取。最后图片都会下载到xfxy文件内,可以通过cnt_pic控制下载图片的数量,如下图所示:

#author:xfxy
#time:2020/04/18from urllib.parse import urlencode
import requests
import time
import os
base_url='https://m.weibo.cn/api/container/getIndex?'
def get_all_weibo(since_id):if since_id==None:return Noneheaders={'Referer': 'https://m.weibo.cn/u/6163257669?from=myfollow_all&is_all=1&sudaref=login.sina.com.cn','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.4040.400','X-Requested-With': 'XMLHttpRequest',}params={'from': 'myfollow_all','is_all': '1','sudaref': 'login.sina.com.cn','type': 'uid','value': '6163257669','containerid': '1076036163257669','since_id': since_id,}url=base_url+urlencode(params)r=requests.get(url,headers=headers)return r.json().get('data').get('cards')items=get_all_weibo('4494845651530130')
start=time.time()
cnt_pic=0
while(1):for item in items:if item.get('mblog')!=None:item=item.get('mblog')else:continueitem = item.get('pics') #获取有图片的微博下各个图片信息的listif item != None:for pic in item:if pic.get('large') != None:url=pic.get('large').get('url') #获取大图下载urltitle = url.split('/')[-1] #从url中获取图片名with open('xfxy\{0}'.format(title),'wb') as f:f.write(requests.get(url).content)cnt_pic=cnt_pic+1if cnt_pic>200: #若下载图片数量大于200,则循环退出breakfor i in range(len(items)):  #寻找最后一条含有mblog字段的card,取其mblog字段中的id作为下一次循环的idif items[len(items)-1-i].get('mblog')!=None:since_id=items[-1].get('mblog').get('id')breakitems=get_all_weibo(since_id)time.sleep(0.5)if items==None or len(items)<=1:breakitems=items[1:]
print("运行时间:",time.time()-start)


由于下载的图片均为大图,如果爬取的图片数量比较多,有大量的时间都会耗费在下载图片上,所以尝试将要爬取的图片下载url整合到一个list之后,通过多进程的方式下载图片,利用该思路修改后的爬取脚本如下所示,通过multiprocessing实现多进程图片下载,大家可以爬取发图片比较多的博主对比一下多进程与单进程的效果,我自己找了一个博主爬取其发过的两百多张图片,单进程与多进程的效果如下面两张图所示,可以看到多进程爬取快了很多:

#author:xfxy
#time:2020/04/18from urllib.parse import urlencode
import requests
import time
from multiprocessing import Pool,freeze_support
base_url='https://m.weibo.cn/api/container/getIndex?'
def get_all_weibo(since_id):if since_id==None:return Noneheaders={'Referer': 'https://m.weibo.cn/u/6163257669?from=myfollow_all&is_all=1&sudaref=login.sina.com.cn','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.4040.400','X-Requested-With': 'XMLHttpRequest',}params={'from': 'myfollow_all','is_all': '1','sudaref': 'login.sina.com.cn','type': 'uid','value': '6163257669','containerid': '1076036163257669','since_id': since_id,}url=base_url+urlencode(params)r=requests.get(url,headers=headers)return r.json().get('data').get('cards')def load_pics(url):title = url.split('/')[-1]with open('yaoyao\{0}'.format(title), 'wb') as f:f.write(requests.get(url).content)if __name__ =='__main__':freeze_support() #在windows下使用multiprocess,由于windows下不是通过fork()产生子进程,所以需要加上freeze_support()items=get_all_weibo('4494883576803454')start=time.time()pic_urls=[]while(1):for item in items:if item.get('mblog')!=None:item=item.get('mblog')else:continueitem = item.get('pics')if item != None:for pic in item:if pic.get('large') != None:url=pic.get('large').get('url')pic_urls.append(url)print(len(pic_urls))if len(pic_urls)>200:breakfor i in range(len(items)):  #寻找最后一条含有mblog字段的card,取其mblog字段中的id作为下一次循环的idif items[len(items)-1-i].get('mblog')!=None:since_id=items[-1].get('mblog').get('id')breakitems=get_all_weibo(since_id)time.sleep(0.5)if items==None or len(items)<=1:breakitems=items[1:]#pool=Pool() # 创建进程池pool.map(load_pics,pic_urls) #第一个参数为函数名,第二个参数为传入函数的参数的迭代器pool.close() #关闭进程池,不再接受新的进程pool.join() #阻塞父进程直到所有子进程结束后再执行父进程print("运行时间:",time.time()-start)


Python高级特性与网络爬虫(一):使用Ajax请求爬取用户微博内容和python多进程爬取用户图片相关推荐

  1. Python高级特性与网络爬虫(二):使用Selenium自动化测试工具爬取一号店商品信息

    上一篇介绍了Ajax动态渲染的页面的分析和爬取,通过JavaScript动态渲染的页面的方式不只有ajax这一种,还有很多其他的方式,分析他们的网页结构和加密参数难度非常大,为了解决这样的页面的数据爬 ...

  2. Python高级特性:切片、迭代、列表生成式、生成器与迭代器

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程 ...

  3. Python高级特性——切片(Slice)

    Python高级特性--切片(Slice) 摘录廖雪峰网站 定义一个list: L = ['haha','xixi','hehe','heihei','gaga'] 取其前三个元素: >> ...

  4. 【Python基础】Python高级特性:切片、迭代、列表生成式、生成器与迭代器

    接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程了.今天的笔记内容是Python高级特性,其中包括快速访问对象类型元素的切片.循环中的迭代意义.方便的列表生成式操作以及生成器和迭代器 ...

  5. Python学习笔记(五) Python高级特性

    Python高级特性 一. 切片 python中提供了切片(Slice)操作符 , 可以方便的获取list或tuple中的某一段元素 . # -*- coding : utf-8 -*- #Pytho ...

  6. Python高级特性——迭代(Iteration)

    Python高级特性--迭代(Iteration) 1.给定一个集合list或者tuple,可以通过for -- in --的语法来实现循环遍历,这个循环我们就叫做迭代 迭代list: >> ...

  7. Go 函数特性和网络爬虫示例

    爬取页面 这篇通过网络爬虫的示例,来了解 Go 语言的递归.多返回值.延迟函数调用.匿名函数等方面的函数特性. 首先是爬虫的基础示例,下面两个例子展示通过 net/http 包来爬取页面的内容. 获取 ...

  8. Python小姿势 - # Python网络爬虫之如何通过selenium模拟浏览器登录微博

    Python网络爬虫之如何通过selenium模拟浏览器登录微博 微博登录接口很混乱,需要我们通过selenium来模拟浏览器登录. 首先我们需要安装selenium,通过pip安装: ``` pip ...

  9. 深入详解python高级特性——函数柯里化(Currying)与反柯里化

    前言:本章的内容本来很简单,但是涉及到的理论部分相对较多,想要彻底弄懂前因后果需要具备以下几个知识点, (1)python的高阶函数 (2)python的装饰器本质 (3)Python的functoo ...

最新文章

  1. ClickHouse Keeper 源码解析
  2. 漫画:程序员战力图鉴
  3. 华为eNSP最稳定的装法
  4. 隔行变色java代码_纯js实现隔行变色效果
  5. Android SystemUI 快捷开关分析
  6. codevs2069 油画 — 动态维护优先队列
  7. 通过爬虫爬取一些图片
  8. 鸿蒙车载系统丰田,华为公布三大鸿蒙车载操作系统
  9. c语言经典案例 俄罗斯方块,C语言实现俄罗斯方块经典游戏课程设计
  10. Android -- 每日一问:在项目中使用AsyncTask会有什么问题吗?
  11. linux系统安装软件报错,Linux安装软件时报错解决方法
  12. [LeetCode 中等 树]545. 二叉树的边界
  13. pycharm运行报错:Process finished with exit code -1073741515 (0xC0000135)
  14. Qt打开图片,维持原宽高比,适应窗口
  15. 2020双十一活动怎么玩?做好这3点引爆销量!
  16. 大数据技术与应用实验报告3
  17. 史上最全的Jackson框架使用教程
  18. Python-int()函数
  19. 【设计模式】--- 装饰器模式、静态代理模式和动态代理模式
  20. app爬虫反编译(一) 之反编译工具

热门文章

  1. vuejs调用支付宝支付页面
  2. 全志V40 HDMI + LVDS实现双屏异显
  3. Playnite 使用指南:高效管理 PC 上所有游戏
  4. 城固一中2021年高考成绩查询,2021年汉中今年的中考成绩
  5. 虚拟服务器磁盘回收,回收VMWare虚拟机占用的磁盘空间
  6. 一篇转载(感谢原作者)
  7. MD版的花瓣网应用源码
  8. JAVA学习16_Java的ISO、UTC、UNIX时间类型转换
  9. 一杯鸡汤,敬给自己的坚持
  10. 多普勒激光雷达数据采集系统