目录

一、Session保持登录

二、代理IP的使用

三、timeout参数

四、retrying模块的使用

五、异步加载动态数据

六、爬虫中数据的分类以及解析

七、json格式数据

八、面向对象改写案例

九、json数据的解析 > jsonpath的使用


一、Session保持登录

在上节我们讲到了人人网的案例,发送携带表单数据的post请求可以成功访问到登录后的页面,如果我们此时想通过此页面去访问别人的主页我们应该怎么做?

import requestsif __name__ == '__main__':# 1.确认目标的url > 登录的urlurl_ = 'http://www.renren.com/PLogin.do'# 用户代理headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}# post请求携带数据,form表单..data_ = {'email': 'xxxxxxxx',  # 账号'password': 'xxxxxxxx'  # 密码}# 2.发送请求response_ = requests.post(url_, headers=headers_, data=data_)str_data = response_.text# 4.保存with open('renren02.html', 'w', encoding='utf-8') as f:f.write(str_data)# 找到详情页url_ > 需要登录之后才能够访问的url_ = 'http://www.renren.com/880151247/profile'response_ = requests.get(url_, headers=headers_)str_data = response_.text# 保存在本地with open('renren_dapeng.html', 'w', encoding='utf-8') as f:f.write(str_data)

通过上述代码我们可以成功访问到人人网登录后的个人主页,但是当访问别人主页的时候,又跳转到了登录页面。

出现这种情况的原因很简单,我们使用的python代码进行访问网站并不是浏览器,所以当我们去访问别人主页时并没有携带登陆后带有登录信息的cookie,这才导致我们访问失败。

搞清楚了原因后解决就变得轻松多了,我们只要在第二次发送请求时带上登陆后的cookie就可以成功了。但是这样的作法也存在着一些问题:

当我们要去访问100个人的主页时,我们要做100次的模拟登陆,然后再去携带100个不同的cookie,就很麻烦,此时我们引出一种更简单的做法。

利用requests的session方法,创建一个session类,利用session发送的请求就会自动携带登录过后保存有登录信息的cookie

import requestsif __name__ == '__main__':# 1.确认目标的url > 登录的urlurl_ = 'http://www.renren.com/PLogin.do'# 用户代理headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}# post请求携带数据,form表单..data_ = {'email': 'xxxxxxx',  # 账号'password': 'xxxxxxx'  # 密码}# 2.如果想要发送post请求,模拟了登录之后,自动携带登陆过后的cookie,就要使用session方法session_ = requests.session()  # 返回一个session对象session_.post(url_, headers=headers_, data=data_)  # 之后session对象就保持了登录信息# 4.保存# with open('renren02.html','w',encoding='utf-8') as f:# f.write(str_data)# 找到详情页url_ > 需要登录之后才能够访问的url_ = 'http://www.renren.com/880151247/profile'  # dapeng# 此时的session是保持了登录状态的,自动携带了带有登录信息的cookieresponse_ = session_.get(url_, headers=headers_)str_data = response_.text# 保存在本地with open('renren_dapeng02.html', 'w', encoding='utf-8') as f:f.write(str_data)

二、代理IP的使用

构造方法与请求头的构造方法一致,也是一个键值对

proxy_ = {# 固定写法'http': 'http://1.1.1.1:8888','https': 'https://1.1.1.1:8888'
}

键名为http或者https,值为 http://IP地址:端口号 或 https://IP地址:端口号

proxy_ = {# 固定写法'http': '1.1.1.1:8888','https': '1.1.1.1:8888'
}

第二种较为简单并且常用,键名与第一种方法一样,值为 IP地址:端口号

import requestsif __name__ == '__main__':url_ = 'https://www.baidu.com/'headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}# 代理IP的构建,以键值对的方式# proxy_ = { # 固定的语法 ip地址:端口号#     'http':'1.1.1.1:8888'# }proxy_ = {  # 固定的语法 ip地址:端口号'http': 'http://1.1.1.1:8888'  # 是一个无效的代理IP}response_ = requests.get(url_, headers=headers_, proxies=proxy_)bytes_data = response_.content# 保存一下with open('baidu01.html', 'wb') as f:f.write(bytes_data)

在访问网站时的用法如上

上述代码中的代理IP是我们瞎编的,为什么还有访问成功呢?因为requests最近更新后,当代理IP使用不成功时,会自动使用本机IP

测试代理IP的有效性:

测试网站:http://2021.ip138.com/

我们既然有了测试IP地址的网站,那么使用代理IP访问该网站就可以测试代理IP是否有效

import requests
from lxml import etree  # 提取html格式数据的if __name__ == '__main__':# 特殊的测试IP的urlurl_ = 'http://2021.ip138.com/'headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}# 代理IP的构建,以键值对的方式# proxy_ = { # 固定的语法 ip地址:端口号#     'http':'1.1.1.1:8888'# }proxy_ = {  # 固定的语法 ip地址:端口号'http': 'http://1.1.1.1:8888'  # 是一个无效的代理IP}response_ = requests.get(url_, headers=headers_, proxies=proxy_)# response_ = requests.get(url_,headers=headers_)# print(response_)str_data = response_.text  # 得到字符串类型的响应文本数据# 提取数据(后面会讲)html_obj = etree.HTML(str_data)res_ = html_obj.xpath('//title/text()')[0]print(res_)

如果程序报错,就证明代理IP无效

当我们使用代理IP池时,我们可以通过循环测试他们的有效性,将有效的代理IP加入到一个空列表中,当循环结束时,这个列表中的代理IP就全是有效的了。

三、timeout参数

当我们访问网站的时候,会出现响应时间过长的情况。

例如:我们在测试代理IP有效性的时候,即使有些代理IP有效,但存在着访问网站获取响应速度过慢的情况,所以我们需要把这样的IP也剔除掉

response_ = requests.get(url_, headers=headers_, proxies=proxy_, timeout=3)

我们在发送请求时加上timeout参数就可以了,例子中 timeout=3 ,就是在3秒内没有获得响应的话就立即报错

四、retrying模块的使用

见名知意,retrying重新尝试,即访问失败时重新发送请求

当我们要发送很多请求时,可能由于网络波动或者其他原因导致极少数的url请求不成功,那么我们是直接放弃这些url的请求吗?答案当然是否定的,我们可以使用retrying模块来实现多给他几次发送请求的机会

retrying模块是个第三方模块,需要自己下载。

我们使用的是retrying模块中的retry,通过查看retry,可以发现他是一个三层嵌套的闭包,用来做带有参数的装饰器,因为装饰器只能对函数和方法进行装饰,所以此处我们需要采用面向对象的编程方法

import requests
from retrying import retry  # 怎么利用retry去创造多几次请求的机会class Demo:def __init__(self):self.url_ = 'xxxx.com'# 设置一个记数的变量self.num_ = 0# 发送请求的发送@retry(stop_max_attempt_number=3)def send_request(self):self.num_ += 1print(self.num_)requests.get(self.url_)  # 报错,导致下面的代码执行不到def run(self):try:self.send_request()except Exception as e:print(e)if __name__ == '__main__':demo = Demo()demo.run()

因为我们要请求的网站是瞎编的,所以请求不会成功,以此我们来测试一下retry功能,retry中有一个参数:stop_max_attempt_number ,最多尝试次数,即我们请求失败时,有多少次重新请求的机会。

五、异步加载动态数据

异步:多任务可以同时进行,而且互不干扰

加载:页面的渲染

动态:页面没有发生跳转的情况下,里面的数据发生了变化

例子:https://movie.douban.com/chart页面右边电影的分类随便选择一类

当我们向下滑动页面时,页面并没有发生变化,但会有新的电影信息加载出来,这就是典型的异步加载的动态数据

分析:

异步加载:既然有新的数据产生,所以必定发送了相应的请求,在例子中就是向下滑动页面时触发了js代码中的ajax,然后发送了请求,获取了响应

动态数据:这些响应中就有数据,而这些数据我们就称之为动态数据

异步加载中说到发送了相应的请求,那必然是对不同的url进行了访问,html格式的一般都是静态数据,因为他是页面架构;动态数据是之后去填充页面的数据,基本上都是json格式。我们想要电影的信息,他是随着我们不断的向下滑动鼠标才能加载出来,即这些数据为动态数据。我们可以在鼠标右键检查的network中的xhr找到对应的动态数据包(动态数据包一般都可以在xhr中找到),我们在豆瓣电影的例子中发现一个动态数据包中有20条数据(20部电影的信息......),当鼠标向下滑动触发了ajax,就有请求发送,新的数据包就随之产生,然后新的数据包对页面进行填充。当向下滑动后,产生新的数据包,就意味着进行了翻页操作,1个url对应20条数据,当我们需要100条数据时,就得找到5个这样的url,而数据包的产生是类似的,即翻页是类似的,那么他们的url是否会存在一定的规律呢?

我们以豆瓣电影的爱情类电影为例:

'''
第一页:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=0&limit=20
第二页:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=20&limit=20
第三页:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=40&limit=20
第四页:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=60&limit=20
第五页:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=80&limit=20
'''

我们通过对比分析,发现只有start的值不同,而且每一页之间的差为20,这就是翻页的规律

import requests
from fake_useragent import FakeUserAgent
import timeif __name__ == '__main__':# 确认要抓取数据的页面个数pages_ = int(input('请输入要抓取数据的页面个数:'))for page_ in range(pages_):# 1.确认目标的urlurl_ = f'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start={20 * page_}&limit=20'# 构造请求头headers_ = {'User-Agent': FakeUserAgent().random}# 2.发送请求response_ = requests.get(url_, headers=headers_)content_ = response_.content# 3.解析数据(略)# 4.保存数据with open(f'豆瓣{page_ + 1}.json', 'wb') as f:f.write(content_)# 降低请求频率,防止被反爬time.sleep(1)

我们现在需要五个页面的数据,即需要对页面发送请求,而且他们的url存在规律,每个url中start的值相差20,所以我们可以用一个循环。一到五页的start值为:0,20,40,60,80,range(pages_)的值分别为0,1,2,3,4,所以代码中的start值应该为page_ * 20

六、爬虫中数据的分类以及解析

Python中一般都是操作字符串类型的数据

json格式数据的提取,解析:需要一个第三方库:jsonpath,re作为辅助

html格式数据的提取,解析:xpath,re作为辅助

七、json格式数据

爬虫部分:我们从前端拿到(爬到)的json格式的数据,应该怎么转换成为python能够操作的数据呢?

后端部分:我们python提供的数据,怎么转换成为json格式的数据供前端使用呢?

python 转 json 用json中的dumps方法

import jsonif __name__ == '__main__':# python中的字典python_data = {'name': '小明','age': '18',}print(type(python_data), python_data)# <class 'dict'> {'name': '小明', 'age': '18'}# python转json 用dumps函数,如果需要显示中文,需要添加参数json_data = json.dumps(python_data)print(type(json_data), json_data)# <class 'str'> {"name": "\u5c0f\u660e", "age": "18"}json_data = json.dumps(python_data, ensure_ascii=False)print(type(json_data), json_data)# <class 'str'> {"name": "小明", "age": "18"}# 如果需要格式更加美观,需要添加一个indent参数json_data = json.dumps(python_data, ensure_ascii=False, indent=3)print(json_data)'''{"name": "小明","age": "18"}'''

需要注意的是:

1.我们定义python中字典是用的都是单引号,在转换成json格式后,所有单引号变成了双引号,这是因为json中的引号必须是双引号

2.我们定义python中字典时在最后面加了个逗号,在转换成json格式后,末尾的逗号消失了,这是因为json格式中末尾不能有逗号

3.python转json格式时如果不加参数:ensure_ascii=False,那么python格式中的中文在转化成json格式后会出现乱码

json 转 python 用json中的loads方法

import jsonif __name__ == '__main__':# python中的字典python_data = {'name': '小明','age': '18'}print(type(python_data), python_data)# <class 'dict'> {'name': '小明', 'age': '18'}json_data = json.dumps(python_data, ensure_ascii=False, indent=3)print(type(json_data), json_data)'''<class 'str'> {"name": "小明","age": "18"}'''# json 转 python 用loads函数py_data = json.loads(json_data)print(type(py_data), py_data)# <class 'dict'> {'name': '小明', 'age': '18'}

如何将python字典写入json文件?

import jsonif __name__ == '__main__':file = open('json01.json', 'w')# 创建一个python字典python_dict = {'name': '小明','age': 18}# 将python字典写入json文件用dump方法# 正常显示中文需要添加参数ensure_ascii=False,格式好看需要加入一个参数indentjson.dump(python_dict, file, ensure_ascii=False, indent=3)

如何将json文件读入python转化为字典格式?

import jsonif __name__ == '__main__':file = open('json01.json', 'r')# 将json文件读入python转化为字典格式用loadpy_data = json.load(file)print(py_data)  # {'name': '小明', 'age': 18}

总结:

loads:json字符串        >        python

load:json文件        >        python

dumps:python        >        json字符串

dump:python        >        json文件

八、面向对象改写案例

非常繁琐,不是很推荐

import requests
import timeclass DouBan:def __init__(self):"""定义静态的属性,url,User-Agent"""self.url_ = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&limit=20'self.headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}def send_request(self, params_):  # url传参"""发送请求,获取响应"""response_ = requests.get(self.url_, headers=self.headers_, params=params_)str_data = response_.textreturn str_datadef save_file(self, page, str_data):"""保存文件"""with open(f'{page + 1}.json', 'w', encoding='utf-8') as f:f.write(str_data)def run(self):"""调度方法"""pages = int(input('请输入想要抓取的页数:'))for page in range(pages):# 定义url的start参数params_ = {'start': page * 20}# 调用发送请求的方法data_ = self.send_request(params_)# 调用保存的方法self.save_file(page, data_)# 降低请求频率,避免被反爬time.sleep(1)if __name__ == '__main__':douban_ = DouBan()douban_.run()

九、json数据的解析 > jsonpath的使用

网站:json.cn        把json格式的数据复制进去,可以使结构更美观,清晰

使用方法举例:

import jsonpathdata_ = { "store": {"book": [ { "category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95},{ "category": "fiction","author": "Evelyn Waugh","title": "Sword of Honour","price": 12.99},{ "category": "fiction","author": "Herman Melville","title": "Moby Dick","isbn": "0-553-21311-3","price": 8.99},{ "category": "fiction","author": "J. R. R. Tolkien","title": "The Lord of the Rings","isbn": "0-395-19395-8","price": 22.99}],"bicycle": {"color": "red","price": 19.95}}
}# 使用方法
res_ = jsonpath.jsonpath(data_,'$.store.book[*].author')
JSON路径 结果
$.store.book[*].author 商店中所有书籍的作者
$..author 所有的作者
$.store.* 商店下所有的元素
$.store..price 商店中所有内容的价格
$..book[2] 第三本书
$..book[(@.length-1)] | $..book[-1:] 一本书
$..book[0,1] | $..book[:2] 前两本书
$..book[?(@.isbn)] 获取有isbn的所有数
$..book[?(@.price<10)] 获取价格大于10的所有的书
$..* 获取所有数据

使用方法:jsonpath.jsonpath(对象,jsonpath路径)

使用jsonpath提取到的数据是一个列表

jsonpath的语法并不固定,要取同一个内容,jsonpath路径可能不同

注意:

简单方法中是使用了response的json方法,不是导入的json模块

# 将得到的json格式的数据转换为python能够操作的格式
data_ = response_.text
py_data = json.loads(data_)# 简单方法
py_data = response_.json()

实际使用(豆瓣电影):

import jsonpath
import requests
import jsonif __name__ == '__main__':# 1.确认目标urlurl_ = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=0&limit=20'# 构造用户代理headers_ = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}# 2.发送请求,获取响应response_ = requests.get(url_, headers=headers_)# 转换为python格式py_data = response_.json()# 3.解析 title scoretitle_list = jsonpath.jsonpath(py_data, '$..title')  # 列表score_list = jsonpath.jsonpath(py_data, '$..score')print(title_list)print(score_list)# 4.保存for i in range(len(title_list)):  # 一条一条数据写入,,让格式看起来更舒服dict_ = {}dict_[title_list[i]] = score_list[i]# 转成json字符串写入json_data = json.dumps(dict_,ensure_ascii=False) + ',\n'  # 显示中文 换行with open('duoban_03.json', 'a', encoding='utf-8') as f:  # 进行追加不覆盖f.write(json_data)

Python爬虫(第四周)相关推荐

  1. python爬虫项目实战教学视频_('[Python爬虫]---Python爬虫进阶项目实战视频',)

    爬虫]---Python 爬虫进阶项目实战 1- Python3+Pip环境配置 2- MongoDB环境配置 3- Redis环境配置 4- 4-MySQL的安装 5- 5-Python多版本共存配 ...

  2. python爬虫 - python requests网络请求简洁之道

    转自:python爬虫 - python requests网络请求简洁之道 requests简介 requests是一个很实用的Python HTTP客户端库,编写爬虫和测试服务器响应数据时经常会用到 ...

  3. Python爬虫数据分析毕业论文,Python爬虫数据可视化

    如何用Python爬虫抓取网页内容? 爬虫流程其实把网络爬虫抽象开来看,它无外乎包含如下几个步骤模拟请求网页.模拟浏览器,打开目标网站.获取数据.打开网站之后,就可以自动化的获取我们所需要的网站数据. ...

  4. 关于Python爬虫原理和数据抓取1.1

    为什么要做爬虫? 首先请问:都说现在是"大数据时代",那数据从何而来? 企业产生的用户数据:百度指数.阿里指数.TBI腾讯浏览指数.新浪微博指数 数据平台购买数据:数据堂.国云数据 ...

  5. python爬虫之Scrapy框架的post请求和核心组件的工作 流程

    python爬虫之Scrapy框架的post请求和核心组件的工作 流程 一 Scrapy的post请求的实现 在爬虫文件中的爬虫类继承了Spider父类中的start_urls,该方法就可以对star ...

  6. python爬虫抓取信息_python爬虫爬取网上药品信息并且存入数据库

    我最近在学习python爬虫,然后正好碰上数据库课设,我就选了一个连锁药店的,所以就把网上的药品信息爬取了下来. 1,首先分析网页 2,我想要的是评论数比较多的,毕竟好东西大概是买的人多才好.然后你会 ...

  7. python爬虫案例_推荐上百个github上Python爬虫案例

    现在学生都对爬虫感兴趣,这里发现一些好的github开源的代码,分享给各位 1.awesome-spider 该网站提供了近上百个爬虫案例代码,这是ID为facert的一个知乎工程师开源的,star6 ...

  8. Python培训分享:python爬虫可以用来做什么?

    爬虫又被称为网络蜘蛛,它可以抓取我们页面的一些相关数据,近几年Python技术的到来,让我们对爬虫有了一个新的认知,那就是Python爬虫,下面我们就来看看python爬虫可以用来做什么? Pytho ...

  9. 玩转 Python 爬虫,需要先知道这些

    作者 | 叶庭云 来源 | 修炼Python 头图 | 下载于视觉中国 爬虫基本原理 1. URI 和 URL URI 的全称为 Uniform Resource Identifier,即统一资源标志 ...

  10. 买不到口罩怎么办?Python爬虫帮你时刻盯着自动下单!| 原力计划

    作者 | 菜园子哇 编辑 | 唐小引 来源 | CSDN 博客 马上上班了,回来的路上,上班地铁上都是非常急需口罩的. 目前也非常难买到正品.发货快的口罩,许多药店都售完了. 并且,淘宝上一些新店口罩 ...

最新文章

  1. 解决kalilinux: E: 无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用) E: 无法对目录 /var/lib/apt/lists/
  2. 人工智能顶会WSDM2021 Best Paper Award 发布!
  3. 基matlab的水果识别的应用,基于MATLAB的水果识别的数字图像处理
  4. # 可视化工具资源汇总
  5. 竹子博客Linux,linux学习--美化自己的centos7
  6. php 运行外部程序_PHP实现执行外部程序的方法详解
  7. python可以这样学豆瓣_python爬虫学习之路:豆瓣爬虫练习
  8. log4j:WARN No appenders could be found for logger
  9. 2寸的照片长宽各是多少_贵州公务员考试照片尺寸要求是多少
  10. python 绘制柱状图
  11. 把SQLAlchemy查询对象转换成字典/json使用(分开)
  12. 2021年中国传送控制器市场趋势报告、技术动态创新及2027年市场预测
  13. java ipa签名_iOS苹果应用IPA一键签名工具及重签教程
  14. 数据结构(直接插入排序、希尔排序、直接选择排序、堆排序、冒泡排序、快速排序)
  15. ACER 4741G
  16. 产品读书《认知盈余》
  17. php telnet 交换机,华为S2700交换机配置Telnet
  18. 程序员常用官网和工具站
  19. JAVA Signal Handing
  20. 计算机网络网卡作用是什么,什么是网卡?它的作用是什么?

热门文章

  1. JavaScript中Long型时间格式转标准格式
  2. Reason: Failed to determine a suitable driver class
  3. 健脾养胃粥品之--------小米山药粥
  4. 教师职业生涯随笔————关键实习事件
  5. PCB自己画DIP40引脚封装
  6. 手机桌面上的计算机为什么不能删除,为什么便签删不掉?电脑桌面的便签删不掉...
  7. 时间戳转化为年、月、日、时、分、秒。
  8. 【mkl】: ImportError: No module named mkl
  9. Python 最简单的实例:手机通讯录
  10. Python 爬虫(五):PyQuery 框架