0913~0918
0913(周一)内容概要
- 作业讲解
- 获取数据的途径
- 爬虫及分类
- 网页组成(HTML)
0913内容详细
作业讲解
# 基于pymysql模块操作MySQL实现用户注册登录
'''简易版本(必会)'''
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
passwd='123',
db='db8',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
def register():
# 1.获取用户数据
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 2.校验用户名是否已存在
sql = 'select * from userinfo where name=%s'
cursor.execute(sql, username)
res = cursor.fetchall()
if res:
print('用户名已存在')
else:
sql = 'insert into userinfo(name,password) values(%s,%s)'
cursor.execute(sql, (username, password))
print('%s注册成功' % username)
def login():
# 1.获取用户名和密码
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 2.检验是否存在当前用户
sql = 'select * from userinfo where name=%s'
cursor.execute(sql, username)
res = cursor.fetchall() # [{}]
if res: # 用户名存在
# 校验密码是否正确
user_dict = res[0]
if str(user_dict.get('password')) == password:
print('登录成功')
else:
print("密码错误")
else:
print('用户名不存在')
func_dict = {'1': register, '2': login}
while True:
print("""
1.注册
2.登录
""")
choice = input('choice>>>:').strip()
if choice in func_dict:
func_name = func_dict.get(choice)
func_name()
else:
print('命令不存在')
'''封装版本'''
import pymysql
def get_link():
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
passwd='123',
db='db8',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
return cursor
def auth_user(cursor):
# 1.获取用户数据
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 2.校验用户名是否已存在
sql = 'select * from userinfo where name=%s'
cursor.execute(sql, username)
res = cursor.fetchall()
return username, password, res
def register(cursor):
username, password, res = auth_user(cursor)
if res:
print('用户名已存在')
else:
sql = 'insert into userinfo(name,password) values(%s,%s)'
cursor.execute(sql, (username, password))
print('%s注册成功' % username)
def login(cursor):
username, password, res = auth_user(cursor)
if res: # 用户名存在
# 校验密码是否正确
user_dict = res[0]
if str(user_dict.get('password')) == password:
print('登录成功')
else:
print("密码错误")
else:
print('用户名不存在')
func_dict = {'1': register, '2': login}
cursor = get_link()
while True:
print("""
1.注册
2.登录
""")
choice = input('choice>>>:').strip()
if choice in func_dict:
func_name = func_dict.get(choice)
func_name(cursor)
else:
print('命令不存在')
常见收集数据网站
-
白嫖类
百度指数:https://index.baidu.com/v2/index.html#/ 新浪指数:https://data.weibo.com/index 国家数据:http://www.gov.cn/shuju/index.htm 世界银行:https://data.worldbank.org.cn/ 纳斯达克:https://www.nasdaq.com/zh/market-activity 联合国:http://data.un.org/
-
付费类
国内 艾瑞咨询:https://www.iresearch.com.cn/ 国际 埃森哲:https://www.accenture.com/cn-zh 麦肯锡:https://www.mckinsey.com.cn/ 第三方平台 数据堂:https://www.datatang.com/ 贵阳大数据:http://gbdex.bdgstore.cn/
网络爬虫理论
# 1.什么是互联网?
互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,像一张网一样
# 2.互联网建立的核心目的?
互联网的核心价值在于数据的共享/传递:数据是存放于一台台计算机上的,而将计算机互联到一起的目的就是为了能够方便彼此之间的数据共享/传递,否则你只能拿U盘去别人的计算机上拷贝数据了
# 3.什么是上网?
我们所谓的上网便是由用户端计算机发送请求给目标计算机,将目标计算机的数据下载到本地的过程
# 4.爬虫要做的是什么?
跳过代码模拟网络请求获取数据并解析数据最后保存
# 5.爬虫的价值
如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的猎物/数据
互联网中最有价值的便是数据,比如天猫商城的商品信息,链家网的租房信息,雪球网的证券投资信息等等,这些数据都代表了各个行业的真金白银,可以说,谁掌握了行业内的第一手数据,谁就成了整个行业的主宰,如果把整个互联网的数据比喻为一座宝藏,那我们的爬虫课程就是来教大家如何来高效地挖掘这些宝藏,掌握了爬虫技能,你就成了所有互联网信息公司幕后的老板,换言之,它们都在免费为你提供有价值的数据。
'''爬虫学的好 牢饭吃到饱'''
爬虫的分类
# 1.通用爬虫
搜索引擎用的爬虫系统
尽可能把互联网所有的网页下载放到本地服务器形成备份,再对这些网页做相关处理(提取关键字、去掉广告)最后给用户提供检索结果
1.搜索引擎如何获取一个网站URL
1.主动向搜索引擎提交网址
网址收录:https://ziyuan.baidu.com/site/index
2.在其他网址设置网站外链
3.与DNS服务商合作(DNS即域名解析技术)
简便获取ip地址:ping URL -t
2.通用爬虫并不是万物皆可爬需要遵循robots协议
协议内会指明可以爬取网页的那些部分(...百度快照...)
'''该协议一般只有大型搜索引擎会遵循'''
3.通用爬虫工作流程
爬取网页 存储数据 内容处理 提供检索及排名服务
排名:
1.PageRank值
根据网站的流量(点击、浏览、人气)统计
2.竞价排名
没有money解决不了的事情
# 2.聚焦爬虫
爬虫程序员写的针对指定内容的爬虫
网页组成
浏览器请求数据展示的界面其实内部对应就是一堆HTML代码
爬虫程序说白了就是对这一对HTML代码做数据筛选
所以写好爬虫程序的第一步就是熟悉HTML代码基本组成
HTML:超文本标记语言
# 浏览器可以展示出来的界面都是由HTML构成的
eg:淘宝 天猫 京东 链家
前端与后端
前端
任何与用户直接打交道的操作界面都可以称之为"前端"
后端
程序员编写的运行在程序内部不直接与用户打交道的程序代码
一般都是指代程序员编写的代码
前端三剑客
HTML 网页的骨架
CSS 网页的样式
JavaScript(JS) 网页的动态效果
HTML基本组成
# 网页文件一般都是以.html结尾
# HTML语法结构
<html>
<head>书写的一般都是给浏览器看的</head>
<body>书写的就是浏览器要展示给用户看的</body>
</html>
# head内常见标签(了解)
title 定义网页标题
style 内部直接书写css代码
link 引入外部css文件
script 内部可以直接书写js代码也可以引入外部js文件
meta 定义网页源信息
<meta name="description" content="京东JD.COM-专业的综合网上购物商城,为您提供正品低价的购物选择、优质便捷的服务体验。商品来自全球数十万品牌商家,囊括家电、手机、电脑、服装、居家、母婴、美妆、个护、食品、生鲜等丰富品类,满足各种购物需求。">
<meta name="Keywords" content="网上购物,网上商城,家电,手机,电脑,服装,居家,母婴,美妆,个护,食品,生鲜,京东">
body内常见标签
# html标签分类
双标签(有头有尾)
<a></a>
单标签(自闭和)
<img/>
# 基本标签
h1~h6
u、s、i、b
p
hr、br
0914(周二)内容概要
-
特殊符号
-
常用标签
-
列表标签
-
表格标签
-
表单标签
-
正则表达式
爬虫就是从网页一堆数据当中筛选出符合我们要求的数据 这个就是正则表达式可以实现的功能
0914内容详细
特殊符号
空格
> >
< <
& &
¥ ¥
版权 ©
注册 ®
常用标签
<a href="https://www.sogo.com">链接标签</a>
href参数后面写网址 用户点击即可跳转到该网页
<img src="111.png" alt="">图片标签
src参数后面写图片的地址 可以是网络上的也可以是本地的
<div>页面布局标签</div>
是所有网页中出现频率最高的标签 内部可以无限制的嵌套任意标签
<span>页面文本标签</span>
是所有网页中涉及到文字可能会出现的标签 频率并不是太高
列表标签
<ul>
<li>001</li>
<li>002</li>
<li>003</li>
<li>004</li>
<li>005</li>
</ul>
"""在网页上看似有规则排列的横向或者竖向的内容基本都是用列表标签完成的"""
表格标签
'''涉及到多条相同格式数据展示的时候可以考虑使用表格标签(类似于excel)'''
<table>
<thead>
<tr>
<th>序号</th> <!--书写一个个字段名-->
<th>姓名</th>
<th>年龄</th>
</tr> <!--一个tr就是一行-->
</thead> <!--书写表头数据(字段名)-->
<tbody>
<tr>
<td>1</td> <!--书写一个个真实数据-->
<td>jason</td>
<td>123</td>
</tr>
</tbody> <!--书写表单数据(真实数据)-->
</table>
表单标签
"""涉及到用户数据的获取一般都需要使用表单标签"""
input标签
type参数
text 普通文本
password 密文展示
email 邮箱格式
date 日期格式
radio 单选
checkbox 多选
file 文件
submit 提交按钮
reset 重置按钮
button 普通按钮
select标签
option子标签
textarea标签
获取大段文本
标签特性(重要)
<a id='' class=''></a>
上述id、class等都称之为a标签的属性
"""标签两大核心属性"""
id # 单独查找某个人
类似于标签的身份证号码 用于唯一标识标签
在同一个html文档中id不能重复
class # 批量查找一群人
类似于标签的种群(类别) 用于区分不同的类
在用一个html文档中class值可以重复 表示属于同一个类别
eg:
<p class='c1'></p>
<a class='c1'></a>
<div class='c1'></div>
一个标签可以含有多个class值
<span class='c1 c2 c3'></span>
"""标签还可以自定义任意的属性"""
<a username='jyb' pwd=123></a>
"""标签之间的关系描述"""
<div>只要是div内部的标签都可以称之为是div的后代
<a>上一级div的儿子</a>
<p>上一级div的儿
<span>上一级p的儿上上一级div的孙子</span>
</p>
<div>上一级div的儿
<a>上一级div的儿子上上一级div的孙子</a>
</div>
<span>上一级div的儿</span>
</div>
正则表达式
# 前戏
'''纯python代码实现数据校验'''
# 1.获取用户手机号
phone = input('phone num>>>:').strip()
# 2.先判断长度是否是11位
if len(phone) == 11:
# 3.再判断是否是纯数字
if phone.isdigit():
# 4.最后判断开头是否是13 14 15 18
if phone.startswith('13') or phone.startswith('14') or phone.startswith('15') or phone.startswith('18'):
print('是一个合法的手机号')
else:
print('手机号格式错误')
else:
print('手机号必须是纯数字')
else:
print('手机号必须是11位')
'''借助于正则表达式校验'''
import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
print('是合法的手机号码')
else:
print('不是合法的手机号码')
# 使用正则表达式可以极大的简化数据筛选和校验的步骤
"""
有时候匹配的内容很精确的情况下可以直接写具体内容
eg:
待匹配的文本内容 jasonkevinjasontonyegonjack
要匹配的文本 jyb
正则表达式直接写jyb即可
"""
正则表达式之字符组
# 字符组在匹配内容的时候是单个单个字符挨个匹配
[0123456789] 匹配0到9之间的任意一个数字包括首尾
[0-9] 简写:匹配0到9之间的任意一个数字包括首尾
[a-z] 匹配小写字母a到z之间的任意一个字母包括首尾
[A-Z] 匹配大写字母A到Z之间的任意一个字母包括首尾
[0-9a-zA-Z] 匹配数字或者小写字母或者大写字母
正则表达式之符号
# 符号在匹配内容的时候是单个单个字符挨个匹配
. 匹配除换行符以外的任意字符
\d 匹配数字
^ 匹配字符串的开始
$ 匹配字符串的结尾
a|b 匹配字符a或字符b
() 给正则表达式分组 本身没有任何意义
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符(取反)
正则表达式之量词
# 跟在正则表达式的后面可以一次性匹配多个字符
'''量词必须跟在正则表达式后面 不能单独出现使用'''
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
"""正则表达式默认情况下都是贪婪匹配>>>:尽可能多的匹配"""
正则 待匹配的文本 结果
海. 海燕海娇海东 三个结果 海燕、海娇、海东
^海. 海燕海娇海东 一个结果 海燕
海.$ 海燕海娇海东 一个结果 海东
海.* 海燕海娇海东 一个结果 海燕海娇海东
练习题
李.? 李杰和李莲英和李二棍子 李杰
李莲
李二
# 问号表示零次或一次 默认贪婪即一次 其实就是正则表达式本身的一次
李.* 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子
李.+ 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子
李.{1,2} 李杰和李莲英和李二棍子 李杰和 李莲英 李二棍
"""贪婪匹配与非贪婪匹配"""
<.*> <script>123</script> <script>123</script>
右侧尽可能多的匹配大括号最后一个才停止
# 将贪婪匹配变成非贪婪匹配只需要在量词后面加一个问号即可
<.*?> <script>123</script>
右侧遇到一个大括号就停止匹配
取消转义
\n 匹配的是换行符
\\n 匹配的是\n
\\\\n 匹配的是\\n
re模块
# 如果想在python代码中使用正则表达式需要借助于内置模块re
import re
text = '<script>123</script>'
res = re.findall('<.*?>',text)
print(res)
0915(周三)内容概要
- re模块
- 爬虫入门模块之requests
- 网络请求的方式
- requests模块实战演练
- cookie与session
0915内容详细
re模块
import re
s = """
eva jyb tony yuan
jyb jyb
jyb a
"""
# ret = re.findall('j.*?n', s) # 返回所有满足匹配条件的结果,放在列表里
# print(ret)
"""
findall(正则,文本数据)
在匹配的时候是全局匹配不会因为匹配到一个就停止
返回的结果是一个列表 内部包含正则匹配到的所有的内容
"""
# 暂时了解
# res = re.finditer('j.*?n', s)
# for i in res:
# print(i.group())
"""
finditer(正则,文本数据)
返回的结果是一个迭代器(更加节省内存) 只有主动索要才会产生数据 否则永远只占一块空间
"""
# 匹配到一个符号条件的数据就结束
# res = re.search('j.*?n', s)
# print(res)
# 只能从头开始匹配 头部不符合直接停止
# res1 = re.match('j.*?n', s)
# print(res1)
import re
ret = re.findall('www.(oldboy).com', 'www.oldboy.com')
print(ret)
"""
findall分组优先展示
会优先展示括号内正则表达式匹配到的内容
"""
ret1 = re.findall('www.(?:oldboy).com', 'www.oldboy.com')
print(ret1)
# 取消分组优先展示
ret2 = re.findall('www.(?:oldboy).com', 'www.oldboy.com')
print(ret2)
# ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
# print(ret)
爬虫模块之requests
# 作用
可以模拟浏览器发送网络请求获取数据
# 先下载
pip3 install requests
1.切换源
2.针对报错
# 再导入
import requests
网络请求方法
网络方法一般有八个之多 但是目前需要我们掌握的只有两个
# get请求
朝别人索要数据
eg:浏览器地址栏输入百度网址回车其实就是在发送get请求朝百度服务器索要百度首页
get请求也可以携带额外的数据 但是数据量有限制最多2~4KB 并且是直接写在网址的后面
url?xxx=yyy&zzz=mmm
# post请求
朝别人提交数据
eg:用户注册登录需要输入用户名和密码之后点击按钮发送post请求将数据提交给远程服务器
post请求也可以携带额外的数据 并且数据大小没有限制 敏感性的数据都是由post请求携带
数据放在请求体中
HTTP协议
# 规定了浏览器与服务端之间数据交互的方式
1.四大特性(重要)
1.基于请求响应
2.基于TCP、IP作用于应用层之上的协议
3.无状态
不保存客户端的状态
eg:
纵使见她千百遍 我都待她如初见
4.无连接
2.数据请求格式(重要)
请求数据格式
请求首行(请求方法 地址...)
请求头(一大堆K:V键值对)
请求体(get请求没有请求体 post请求有 里面是敏感数据)
响应数据格式
响应首行(响应状态码 协议版本...)
响应头(一大堆K:V键值对)
响应体(一般都是给浏览器展示给用户看的数据)
3.响应状态码(重要)
用简单的数字来表示一串中文意思(制定暗号)
1XX:服务端已经成功接收到了你的数据正在处理 你可以继续提交或者等待
2XX:200 OK请求成功服务端发送了响应
3XX:重定向(原本想访问A页面但是内部自动跳到了B页面)
4XX:403请求不符合条件 404请求资源不存在
5XX:服务器内部错误
"""
公司还会自己自定义响应状态码(HTTP的状态码太少不够用)
10001
10002
参考网址:聚合数据
"""
requests模块基本使用
发送网络请求
import requests
requests.get(url) # 发送get请求
requests.post(url) # 发送post请求
# 1.简单的get请求获取页面并报错
import requests
# 朝百度发送get请求获取首页数据
res = requests.get('https://www.baidu.com/')
# print(res.status_code) # 获取响应状态码
# 指定字符编码
# res.encoding = 'utf8'
# print(res.text) # 获取网页字符串数据
# print(res.content) # 获取bytes类型的数据(在python中可以直接看成是二进制)
with open(r'baidu.html', 'wb') as f:
f.write(res.content)
# 2.携带参数的get请求
requests.get(url,params={})
# 3.如何携带请求头数据
requests.get(url,headers={})
防爬措施
1.校验当前请求是否是浏览器发出的
用于校验的核心就在于请求头里面的User-Agent键值对
只要请求里面含有该键值对就表示你是个浏览器没有则不是浏览器
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
解决措施在请求头中加上即可
requests.get(url,headers={...})
0916(周四)内容概要
- cookie与session
- 代码模拟用户登录
- json格式数据
- ip代理池(高级)
- requests其他方法补充
- 实战环节(各种案例)
0916内容详细
cookie与session
# cookie与session的发明是专门用来解决http协议无状态的特点
http协议无状态 >>>: 不保存用户端状态(记不住)
'''早期的网址不需要保存用户状态 所有人来访问都是相同的数据'''
随着时代的发展越来越多的网址需要保存用户状态(记住你)
cookie:保存在客户端浏览器上面的键值对数据
"""
用户第一次登录成功之后 浏览器会保存用户名和密码
之后访问网站都会自动带着该用户名和密码
"""
session:保存在服务端上面的用户相关的数据
"""
用户第一次登录成功之后 服务端会返回给客户端一个随机字符串(有时候也可能是多个)
客户端浏览器保存该随机字符串之后访问网站都带着该随机字符串
"""
# cookie和session是什么关系:session需要依赖cookie
只要是涉及到用户登录都需要使用到cookie
ps:浏览器也可以拒绝保存数据
cookie实战
"""
1.浏览器network选项中 请求体对应的关键字是Form Data
"""
登录地址:http://www.aa7a.cn/user.php
请求体数据格式
username: 616564099@qq.com
password: 123123
captcha: jv3d
remember: 1
ref: http://www.aa7a.cn/user.php?act=logout
act: act_login
'''写爬虫一定是先使用浏览器研究 再写代码'''
# 1.研究登录数据提交给后端的url地址
# 2.研究登录post请求携带的请求体数据格式
# 3.模拟发送post请求
import requests
res = requests.post('http://www.aa7a.cn/user.php',
data={
"username": "616564099@qq.com",
"password": "lqz123",
"captcha": "kuyb",
"remember": 1,
"ref": "http://www.aa7a.cn/user.php?act=logout",
"act": "act_login"
} # data参数携带请求体数据
)
# 获取cookie数据
# print(res.cookies.get_dict())
user_cookie = res.cookies.get_dict()
"""
用户名或密码错误的情况下返回的cookie数据
{'ECS[visit_times]': '1', 'ECS_ID': '69763617dc5ff442c6ab713eb37a470886669dc2'}
用户名和密码都正确的情况下返回的cookie数据
{
'ECS[password]': '4a5e6ce9d1aba9de9b31abdf303bbdc2',
'ECS[user_id]': '61399',
'ECS[username]': '616564099%40qq.com',
'ECS[visit_times]': '1',
'ECS_ID': 'e18e2394d710197019304ce69b184d8969be0fbd'
}
"""
# 使用cookie访问网站
res1 = requests.get('http://www.aa7a.cn/',
cookies=user_cookie
)
if '616564099@qq.com' in res1.text:
print('登录身份访问')
else:
print('cookie存在错误')
获取大数据
# stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的
import requests
response=requests.get('https://www.shiping.com/xxx.mp4',
stream=True)
with open('b.mp4','wb') as f:
for line in response.iter_content(): # 一行一行读取内容
f.write(line)
json格式
json格式的数据有一个非常显著的特征>>>:引号肯定的双引号
在网络爬虫领域 其实内部有很多数据都是采用的json格式
# 前后端数据交互一般使用的都是json格式
import requests
res = requests.get('https://api.bilibili.com/x/player/pagelist?bvid=BV1QE41147hU&jsonp=jsonp')
print(res.json()) # 可以直接将json格式字符串转换成python对应的数据类型
SSL相关报错(苹果电脑常见)
直接百度搜索即可
IP代理池
有很多网站针对客户端的IP地址也存在防爬措施
eg:比如一分钟之内同一个IP地址访问该网站的次数不能超过30次超过了就封禁该IP地址
针对该防爬措施如何解决?
IP代理池
里面有很多IP地址每次访问从中随机挑选一个
#代理设置:先发送请求给代理,然后由代理帮忙发送(封ip是常见的事情)
import requests
proxies={
'http':'114.99.223.131:8888',
'http':'119.7.145.201:8080',
'http':'175.155.142.28:8080',
}
respone=requests.get('https://www.12306.cn',
proxies=proxies)
Cookie代理池
有很多网站针对客户端的cookie也存在防爬措施
eg:比如一分钟之内同一个cookie访问该网站的次数不能超过30次超过了就封禁该cookie
针对该防爬措施如何解决?
cookie代理池
里面有很多cookie每次访问从中随机挑选一个
respone=requests.get('https://www.12306.cn',
cookies={})
0917(周五)内容概要
- 数据的加载方式(重要)
- 爬取天气数据
- 爬取百度翻译
- 爬取药品许可证
- 蔬菜价格
- 爬取豆瓣电源分类数据
0917内容详细
数据的加载方式(重要)
1.常见的加载方式
朝服务器发请求 页面数据直接全部返回并加载
"""
如何验证数据是直接加载还是其他方式
浏览器空白处鼠标右键 点击查看网页源码 在源码界面搜索对应的数据
如果能收到就表示该数据是直接加载的(你可以直接发送相应请求获取)
"""
2.内部js代码请求
先加载一个页面的框架 之后再朝各项数据的网址发送请求获取数据
"""
如何查找关键性的数据来源 需要借助于浏览器的network监测核对内部请求
请求的数据一般都是json格式
"""
爬取天气数据
# 1.拿到页面之后先分析数据加载方式
# 2.发现历史数据并不是直接加载的
统一的研究方向>>>:利用network查看
# 3.查找到可疑的网址并查看请求方式
如果是get请求那么可以直接拷贝网址在浏览器地址栏访问
# 4.将请求获得的数据稍作分析
https://www.bejson.com/
# 5.利用requests模块朝发现的地址发送get请求获取json数据
# 6.可以研究历史天气数据的url找规律 即可爬取指定月份的数据
import requests
import pandas
res = requests.get(
'http://tianqi.2345.com/Pc/GetHistory?areaInfo%5BareaId%5D=60010&areaInfo%5BareaType%5D=2&date%5Byear%5D=2021&date%5Bmonth%5D=6')
# print(res.json()) # 反序列化成字典之后 比对一下数据在哪个键值对中
real_data_html = res.json().get('data')
'''后期再学 目前先了解'''
df1 = pandas.read_html(real_data_html)[0]
df1.to_excel(r'qianqi.xlsx')
百度翻译
1.在查找单词的时候页面是在动态变化的
2.并且针对单词的详细翻译结果数据是动态请求获取的
3.打开network之后输入英文查看内部请求变化
sug请求频率固定且较高
4.研究sug请求发现每次输入的单词都会朝固定的一个网址发送post请求
并且请求体携带了改单词数据
import requests
keyword = input('请输入你需要查询的单词>>>:')
res = requests.post('https://fanyi.baidu.com/sug',
data={'kw': keyword}
)
data_dict = res.json()
data_list = data_dict.get('data')
for d in data_list:
print(d)
爬取药品许可证
# 需求:爬取药品企业生产许可证详细信息
1.先明确是否需要爬取页面数据 如果需要则先查看数据的加载方式
2.通过network查看得知数据是动态加载的 网页地址只会加载一个外壳
3.通过network点击fetch/xhr筛选动态获取数据的地址和请求方式
4.利用requests模块发送相应请求获取数据 之后再分析
5.利用浏览器点击详情页查找关键数据
http://scxk.nmpa.gov.cn:81/xk/itownet/portal/dzpz.jsp?id=911d4f256300476abb78012427d38c9d
6.由于我们需要爬取详情页的数据所以要验证数据的加载方式
7.详情页核心数据也是动态加载的 发现是post请求并携带了一个id参数
id: 911d4f256300476abb78012427d38c9d
8.通过比对得知id数据与第一次爬取的公司简介里面的id一致 从而得出结论
循环获取格式简介id 然后发送post请求 获取每个公司的详细数据
import requests
res = requests.post('http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList',
data={
"on": "true",
"page": 1,
"pageSize": 15,
"productName":'',
"conditionType": 1,
"applyname":'',
"applysn": ''
}
)
# data_dict = res.json()
# data_list = data_dict.get('list')
# 上述两步合成一步
data_list = res.json().get('list')
"""
数据详情页地址:http://scxk.nmpa.gov.cn:81/xk/itownet/portal/dzpz.jsp?id=911d4f256300476abb78012427d38c9d
核心数据请求地址:http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById
核心数据请求体参数:id:911d4f256300476abb78012427d38c9d
"""
# 循环获取格式id值
for d in data_list:
# 字段取值 获取id值
ID = d.get("ID")
# 发送网络请求
res1 = requests.post('http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById',
data={'id':ID}
)
# 获取数据结果
data_dict = res1.json()
'''结合实际需求 保存相应的数据 文件操作 数据库'''
"""
深入研究
1.多页数据如何获取(思路非常重要)
1.先点击页码查看url的变化
如果数据变化url不变 那么数据肯定是动态加载的
如果数据变化url也变 那么数据可能是直接加载也可能是动态
2.针对上述案例 数据是动态加载 所以需要研究每一次点击页码内部请求
3.研究请求体参数得知数据页由page控制
4.写一个for循环即可
2.数据存储如何实现
今日作业 写入文本文件即可
"""
0918(周六)内容概要
-
实例讲解
-
爬虫解析库之bs4模块
能够帮助我们去页面上查找并筛选出我们需要的数据
-
爬取红牛分公司数据
1.直接自己书写正则表达式 2.借助于bs4模块
0918内容详细
实例讲解
# 爬取北京新发地蔬菜相关数据
我们的需求是获取页面上某一块区域内部的核心数据
那么第一步应该先查看核心数据的加载方式
发现数据并不在网页源码上 说明是内部动态加载的
通过network查看发现内部发送了一个post请求
post请求最为独特的就是请求体数据 所以需要研究一下
import requests
import time
def get_price_data(n):
res = requests.post('http://www.xinfadi.com.cn/getPriceData.html',
data={
"limit": '',
"current": n,
"pubDateStartTime": '',
"pubDateEndTime": '',
"prodPcatid": '',
"prodCatid": '',
"prodName": '',
}
)
data_list = res.json().get('list')
for d in data_list:
pro_name = d.get('prodName')
low_price = d.get('lowPrice')
high_price = d.get('highPrice')
avg_price = d.get('avgPrice')
pub_date = d.get('pubDate')
source_place = d.get('place')
print("""
蔬菜名称:%s
最低价:%s
最高价:%s
平均价:%s
上市时间:%s
原产地:%s
""" % (pro_name, low_price, high_price, avg_price, pub_date, source_place))
time.sleep(1)
"""涉及到多页数据爬取的时候 最好不要太频繁 可以自己主动设置延迟"""
for i in range(1, 5):
time.sleep(1)
get_price_data(i)
爬虫解析库之bs4模块
全名:Beautiful Soup4
是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,Beautiful Soup会帮你节省数小时甚至数天的工作时间
模块下载
pip3 install beautifulsoup4
配套解析器下载
pip3 install lxml
bs4模块基本使用
from bs4 import BeautifulSoup
# 构造一个网页数据
html_doc = """
<html>
<head>
<title>The Dormouse's story</title>
</head>
<body>
<p class="title">
<b>The Dormouse's story</b>
</p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
"""
# 1.构造一个bs4解析器对象
soup = BeautifulSoup(html_doc, 'lxml')
# 2.利用对象的内置方法完成一系列操作
'''必须要掌握'''
# print(soup.a) # 从上往下的第一个a标签 soup.标签名称
# print(soup.p.text) # 获取标签内部的文本 包含内部所有的后代标签文本
# print(soup.a.attrs) # 获取标签内部所有的属性 字典数据类型
# print(soup.a.attrs.get('href'))
# print(soup.a.get('href')) # 可以简写 省略attrs参数
'''了解即可'''
# print(soup.p.children) # 获取标签内部所有的子标签 需要循环取值才可以拿到
# print(soup.p.contents) # 获取标签内部所有的元素 了解即可
# print(soup.p.parent) # 获取标签的父标签
# print(soup.p.parents) # 获取标签的所有祖先标签
bs4核心操作
# 1.find方法 缺陷:只能找符合条件的第一个 该方法的返回结果是一个标签对象
# print(soup.find(name='a')) # 查找指定标签名的标签 默认只找符合条件的第一个
# print(soup.find(name='a',id='link2')) # 查找具有某个特定属性的标签 默认只找符合条件的第一个
# print(soup.find(name='p', class_='title')) # 为了解决关键字冲突 会加下划线区分
# print(soup.find(name='p', attrs={'class': 'title'})) # 还可以使用attrs参数 直接避免冲突
# print(soup.find(name='a', attrs={'id': 'link3'})) # 还可以使用attrs参数 直接避免冲突
# print(soup.find(name='a', attrs={'class': 'c1'})) # class属性查找属于成员运算 有就行
# print(soup.find(attrs={'class': 'c1'})) # name参数不写则表示查找所有符合后续条件的标签
# 2.find_all方法 优势:查找所有符合条件的标签 该方法的返回结果是一个列表
# print(soup.find_all('a')) # name字段可以省略 查找的结果是一个列表
### find_all()使用方式与find一致 知识结果数量不一样而已
# 3.select方法 需要使用css选择器 该方法的返回结果是一个列表
"""
<p></p>
<div>
<a></a>
<p>
<a></a>
</p>
<div><p></p></div>
</div>
<p></p>
<p></p>
1.标签选择器
直接书写标签名即可
2.id选择器
#d1 相当于写了 id='d1'
3.class选择器
.c1 相当于写了 class=c1
4.儿子选择器(大于号) 选择器可以混合使用
div>p 查找div标签内部所有的儿子p
5.后代选择器(空格) 选择器可以混合使用
div p 查找div标签内部所有的后代p
"""
print(soup.select('.title')) # 查找class含有title的标签
# print(soup.select('.sister span')) # 查看class含有sister标签内部所有的后代span
# print(soup.select('#link1')) # 查找id等于link1的标签
# print(soup.select('#link1 span')) # 查找id等于link1标签内部所有的后代span
# print(soup.select('#list-2 .element')) # 查找id等于list-2标签内部所有class为element的标签
# print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其实没必要,一条select就可以了
爬取红牛分公司数据
需求:获取红牛所有分公司详细数据(名称 地址 邮箱 电话)
1.查找数据加载方式 得知是直接加载的
2.朝该网页发送请求获取页面数据之后筛选即可
import requests
from bs4 import BeautifulSoup
# 1.发送get请求获取页面内容
res = requests.get('http://www.redbull.com.cn/about/branch')
# 2.解析页面数据
soup = BeautifulSoup(res.text, 'lxml')
# 3.研究标签特性 精确查找
# 分公司名称数据
h2_tag_list = soup.find_all('h2') # 查找到所有的h2标签对象
# for tag in h2_tag_list:
# print(tag.text)
# 使用列表生成式
title_list = [tag.text for tag in h2_tag_list]
# 分公司地址数据
p1_tag_list = soup.find_all(name='p', attrs={'class': 'mapIco'})
# for tag in p_tag_list:
# print(tag.text)
# 使用列表生成式
addr_list = [tag.text for tag in p1_tag_list]
# 分公司邮箱数据
p2_tag_list = soup.find_all(name='p', attrs={'class': 'mailIco'})
# for tag in p2_tag_list:
# print(tag.text)
email_list = [tag.text for tag in p2_tag_list]
# 分公司电话数据
p3_tag_list = soup.find_all(name='p', attrs={'class': 'telIco'})
# for tag in p3_tag_list:
# print(tag.text)
phone_list = [tag.text for tag in p3_tag_list]
for i in range(len(title_list)):
print("""
公司名称:%s
公司地址:%s
公司邮箱:%s
公司电话:%s
""" % (title_list[i], addr_list[i], email_list[i], phone_list[i]))