python数据分析之爬虫基础:爬虫介绍以及urllib详解
前言
在数据分析中,爬虫有着很大作用,可以自动爬取网页中提取的大量的数据,比如从电商网站手机商品信息,为市场分析提供数据基础。也可以补充数据集、检测动态变化等一系列作用。可以说在数据分析中有着相当大的作用!
页面结构介绍
这里主要介绍HTML的一些简单结构,需要一点前端的知识,可以根据情况直接跳过。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table style="width:200px;height:200px;border:1px solid red">
<!-- table 表格,可以输入table,然后按tab键即可自动补齐
tr 表示行结构
td 表示列结构-->
<tr>
<td>
姓名
</td>
<td>
年龄
</td>
<td>
性别
</td>
</tr>
<tr>
<td>
张三
</td>
<td>
18
</td>
<td>
男
</td>
</tr>
</table>
<!-- ui li表示无序列,无关联关系
ol li表示有序列表,有关联关系
a标签表示超链接,这些结构在爬虫的应用场景中非长广-->
<ul>
<li>铁锅炖大鹅</li>
<li>小鸡炖蘑菇</li>
<li>锅包肉</li>
</ul>
<ol>
<li>奖励自己</li>
<li>睡觉</li>
<li>起床</li>
<li>读书学习</li>
</ol>
<a href="http://dwqttkx.blog.csdn.net">人间无解</a>
</body>
</html>
爬虫相关概念
1、爬虫的概念:
爬虫是一种按照一定规则,自动抓取网页信息的程序或脚本。通俗解释就是爬虫就像一个小机器人,能够自动在互联网上逛网页。它可以把网页上的文字、图片、连接之类的信息抓取下来,然后人们可以用这些信息做数据分析等一系列操作。(通过程序模拟浏览器,去向服务器发送请求,获取相应信息)
2、爬虫核心:
1、爬取网页:爬取整个网页,包含了网页中的所有内容
2、解析数据:将网页中得到的数据进行解析
3、难点:爬虫和反爬虫之间的博弈
3、爬虫的用途:
一、爬虫可以搜索引擎优化。搜索引擎靠爬虫收集网页信息,有了这些信息才能在用户搜索时,提供相应的网页结果。
二、爬虫可以做市场调研。企业可以用爬虫获取竞争对手的产品价格、用户评价等信息,了解市场动态。
三、爬虫可以用来做数据收集。用于学术研究,手机学术文件、统计数据等资料;也可以手机社交媒体的数据,来分析舆情和用户喜好。
4、爬虫分类:
1、通用爬虫:
实例:百度、360、goole等搜索引擎---伯乐在线
功能:访问网页->抓取数据->数据存储->数据处理->提供检索服务
roots协议:一个约定俗成的协议,添加roots.txt文件,来抓取本网站哪些内容不可以被抓取,起不到限制作用,自己写的爬虫无需遵循。
网站排名(SEO):1、根据pagerank算法值进行排名
2、百度竞价排名(这就是看谁的钱比较多)
缺点:1、抓取的数据大多是无用的
2、不能根据用户的需求来竞逐你获取数据
2、聚焦爬虫
功能:根据需求,实现爬虫程序,抓取需要的数据
设计思路:1、确定要爬取的url(如何获取url)
2、模拟浏览器通过HTTP协议访问url,获取服务器返回的HTML(如何访问)
3、解析HTML字符串(根据一定规则提取需要的数据)如何解析
5、反爬手段:
1、User-Agent:User-Agent中文名为用户地阿里,简称UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
2、代理IP:西次代理、快代理
什么是高匿名、匿名和透明代理?区别是什么?
使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP;使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP;使用高匿名代理,对方服务器不知道你使用了代理,也不知道你的真实ID。
3、验证码访问
4、动态加载网页:网站返回的是js数据,并不是网页的真实数据,selenium驱动真实的浏览器发送请求
5、数据加密:分析js代码
urllib库的使用
1、基本使用
首先我们需要导包:
import urllib.request
然后需要定义一个url,也就是我们要访问网页的地址(域名) ,模拟浏览器想发送请求,获取到响应信息。
# 使用urllib来获取百度首页的源码
import urllib.request
# 定义一个url,即我们要访问的地址
url = 'http://www.baidu.com'
# 模拟浏览器向服务端发送请求
response = urllib.request.urlopen(url)
# 获取响应中的页面源码
#read()返回的数据是字节形式的二进制数据,这时我们需要decode进行解码操作
content = response.read().decode('utf-8')
print(content)
2、urllib的一个类型和六个方法:
import urllib.request
url = 'http://www.baidu.com'
response = urllib.request.urlopen(url)
# 一个类型
print(type(response)) # <class 'http.client.HTTPResponse'>
# 六个方法
content = response.read() # 一个字节一个字节的读
content = response.read(5) # 只读取前五个字节
# 一行一行的读取,每次只读取一行
content = response.readline()
# 读取全部行
content = response.readlines()
# 返回状态码,200则逻辑没问题,如果是404、500是有问题的
print(response.getcode())
# 返回url地址
print(response.geturl())
# 返回状态信息,响应头
print(response.getheaders())
3、资源下载
基本语法:
urllib.request.urlretrieve(url,filename)
# url代表的是下载的路径,filename代表文件的名字
import urllib.request
# 下载一个网页
url_page = "http://www.baidu.com"
urllib.request.urlretrieve(url_page, "baidu.html")
# 下载图片
url_img = "https://img1.baidu.com/it/u=2414145851,4105017234&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1067"
urllib.request.urlretrieve(url_img, "jujingyi.jpg")
# 下载视频
url_video ="https://vdept3.bdstatic.com/mda-qkh666t7qtjd02w7/cae_h264/1731906619294350169/mda-qkh666t7qtjd02w7.mp4?v_from_s=hkapp-haokan-nanjing&auth_key=1732795382-0-0-0627520a3ef7ab8203af6dfe76c639de&bcevod_channel=searchbox_feed&pd=1&cr=0&cd=0&pt=3&logid=0182283432&vid=582295739326229165&klogid=0182283432&abtest=122021_2"
urllib.request.urlretrieve(url_video, "shipin.mp4")
4、请求对象的定制
UA介绍:User Agent中文名为用户代理 ,简称UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等。
语法:
request = urllib.request.Request()
import urllib.request
url = 'https://www.baidu.com'
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
print(content) # 我们会发现我们得到的内容相当少,这是因为https是由ssl协议的
上述错误代码便是我们遇到的第一个反爬手段即User Agent。在这里我们说一下url的组成:
协议:http/https,https是有ssl加密的,更加安全
主机:即域名——www.baidu.com
端口号:比如http的端口号为80,https为443,MySQL为3306,oracle为1521,redis为6379,mongodb为27017等
路径:s
参数:?后面的数据
锚点
import urllib.request
url = 'https://www.baidu.com'
headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
# 因为urlopen()方法中不能存储字典,因此headers不能传入,此时需要定制请求对象
request = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
4.1、get请求方式:urllib.parse.quote()
周杰伦的网页域名:https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
需求:获取https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=周杰伦的网页源码
import urllib.request
url ="https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=周杰伦"
headers = {"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
request = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 42-44: ordinal not in range(128)
我们会发现并不能正常运行,而是报了上述错误,这是因为周杰伦三个字超出ASCII码值检索的范围,需要我们把周杰伦三个字变成Unicode编码,这个时候需要用到quote方法。
import urllib.request
import urllib.parse
name = urllib.parse.quote("周杰伦")
url ="https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=name"
headers = {"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
request = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
4.2、get请求方式:urllib.parse.urlencode()
但quote方法的缺点很显然,需要一次次的对中文汉字进行转换,每次都需要调用,相当麻烦!所以我们需要一种新的方法来解决这个问题,而这个方法便是urlencode方法。应用场景:多参数需要进行Unicode编码的时候。
# 获取"https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=周杰伦&sex=男&location=中国台湾"网页源码
import urllib.request
import urllib.parse
data = {"wd":"周杰伦","sex":"男","location":"中国台湾"}
new_data = urllib.parse.urlencode(data)
url = "https://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&"+new_data
headers = {"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
request = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode("utf-8")
print(content)
4.3、post请求方式
POST请求是HTTP协议中的一种请求方法。
POST主要用于向指定的资源提交要被处理的数据。比如在网页表单提交数据(如用户注册、登录信息、发表评论)到服务器时,就经常会用到POST请求。和GET请求相比,POST请求传递的数据不会像GET请求一样直接显示在URL中,这让POST请求更适合传递敏感信息(如密码),因为数据不会在URL中暴露。我们以百度翻译为例:
import urllib.request
import urllib.parse
import json
url = "https://fanyi.baidu.com/sug"
headers = {"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
data = {"kw":"spider"}
# post请求的参数一定要进行编码
data = urllib.parse.urlencode(data).encode("utf-8") # 因为data需要是字节类型的数据,所以此时因该进行编码操作
request = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(request)
content = response.read().decode("utf-8")
content = json.loads(content)
print(content)
最后结果会返回一个json数据。我们可以使用json.loads()方法将json数据转化为python数据。
4.4、ajax的get请求
我们以爬取豆瓣电影第一页数据并下载到本地为例子:
import urllib.request
import urllib.parse
url = "https://movie.douban.com/j/chart/top_list?type=5&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/128.0.0.0 Safari/537.36"}
request = urllib.request.Request(url,headers=headers)
repose = urllib.request.urlopen(request)
content = repose.read().decode('utf-8')
# 下载数据到本地
f = open("豆瓣.json","w",encoding="utf-8")
f.write(content)
f.close()
那么如何批量下载更多数据呢?比如下载前十页为例,我们提供三个方法:
# ajax的get请求豆瓣电影前十页数据并保存到本地,方法一:
# import urllib.request
# import urllib.parse
# url = "https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=0&limit=200"
# headers = {"user-agent":
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
# request = urllib.request.Request(url, headers=headers)
# reponse = urllib.request.urlopen(request)
# content =reponse.read().decode("utf-8")
# f = open("豆瓣shi.json","w",encoding="utf-8")
# f.write(content)
# f.close()
# 方法二:通过函数形式,每一页都调用一次函数以及get方法,以追加的形式把数据写入到文件
# import urllib.request
# import urllib.parse
#
#
# def create_request(page):
# base_url = "https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&"
# headers = {"user-agent":
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
# data = {"start": (page - 1) * 20,
# "limit": 20}
# data = urllib.parse.urlencode(data)
# url = base_url + data
# request = urllib.request.Request(url, headers=headers)
# response = urllib.request.urlopen(request)
# content = response.read().decode("utf-8")
# f = open("douban.json", "a", encoding="utf-8")
# f.write(content)
# f.close()
#
# if __name__ == '__main__':
# start_page = int(input("请输入起始页码:"))
# end_page = int(input("请输入结束页码"))
# for page in range(start_page, end_page + 1):
# # 每一页都有请求对象的定制
# create_request(page)
# 方法三:
import urllib.request
import urllib.parse
def create_request(page):
base_url = "https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&"
headers = {"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}
data = {"start":(page-1)*20,
"limit":20}
data = urllib.parse.urlencode(data)
url = base_url + data
request = urllib.request.Request(url,headers = headers)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open("douban"+str(page)+".json","w",encoding="utf-8") as f:
f.write(content)
if __name__ == '__main__':
start_page = int(input("请输入起始页码:"))
end_page = int(input("请输入结束页码"))
for page in range(start_page, end_page+1):
# 每一页都有请求对象的定制
request = create_request(page)
content = get_content(request)
down_load(page,content)
个人建议以第三种方法来开发,因为它更加贴合于企业的项目开发。
4.5、ajax的post请求
import urllib.request
import urllib.parse
def create_quest(page):
base_url = "https://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname"
headers ={
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
data = {
"cname": "郑州",
"pid":None,
"pageIndex": page,
"pageSize": 10
}
new_data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(base_url, new_data, headers)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
# import json
# content = json.loads(content)
# content = content["Table1"]
# for i in content:
# position = i["addressDetail"]
# print(position)
return content
def down_load(content,page):
with open("肯德基"+str(page)+".json","w",encoding="utf-8") as f:
f.write(content)
if __name__ == '__main__':
start_page = int(input("请输入起始页码:"))
end_page = int(input("请输入终止页码:"))
for page in range(start_page,end_page+1):
# 请对象的定制
request = create_quest(page)
# 获取网页源码
content = get_content(request)
# 下载
down_load(content,page)
总体来说和上一个案例套路基本一致,把基础打牢,应该可以轻松解决!
URLError/HTTPError
简介:1、HTTPError类是URLError类的子类
2、导入的包urllib.error.HTTPError urllib.error.URLError
3、http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。
4、通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加稳定,可以通过异常捕获来优化代码
import urllib.request
import urllib.error
url = "https://blog.csdn.net/2301_80109683/article/details/1439772511"
headers ={
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
try:
request = urllib.request.Request(url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
except urllib.error.HTTPError as e:
print(e)
Cookie登录
Cookie登录是网站用来识别用户身份的一种方式。用户首次登陆成功后,网站服务器会生成含用户登录信息的Cookie并发送浏览器保存。再次访问是,浏览器自动发送Cookie给服务器,服务器借此确认身份,使用户免重复输账号密码。其优点是方便快捷、减轻服务器负担,缺点是存在安全风险与隐私问题。
# 微薄的cookie登录,使用场景:数据采集时,需要绕过登录,然后进入到某个页面
import urllib.request
url = "https://weibo.cn/7860977321/info"
headers ={
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
# cookie中携带着登录信息,如果有登陆之后的cookie,我们可以携带着cookie进入到任何页面
'cookie':
'_T_WM=dc6e834b939c02f2cf63eae686703cdb; SCF=AqLqfxclF7261sAej5VukiKWtyKwQC6YWhOjr-DxKfiRwoK4a_pkJ1Wynkwvwq8P2VKl0StItmmIaH0dNf_4sok.; SUB=_2A25KSEBRDeRhGeFG7VIY9ynPyT2IHXVpJN2ZrDV6PUJbktANLU_3kW1NeTtdpWKPQR6WSGxb8AKZSDUfjZ1abI_S; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W56bhEyW3jnAWOeE1zBXWuj5NHD95QN1hq71KMNe0zpWs4DqcjMi--NiK.Xi-2Ri--ciKnRi-zNS0nceh.NS0eEeBtt; SSOLoginState=1733046273; ALF=1735638273'
}
request = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode("utf-8")
# 将数据保存到本地
f = open("weibo.html", "w", encoding="utf-8")
f.write(content)
f.close()
# 如果不加cookie,我们打开HTML文件是一片空白,这是因为请求头信息不够,因此访问不成功
Handler处理器
Handler处理器用于处理各种不同类型的URL请求。他是构建自定义网络请求处理流程的关键部分,通过不同类型的handler可以实现对HTTP、HTTPS、FTP等协议请求的定制化操作,包括处理Cookie、代理、认证等功能。
# handler处理器基本使用,使用handler访问百度来获取网页源码
import urllib.request
url = 'http://www.baidu.com'
headers ={
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
request = urllib.request.Request(url, headers=headers)
# 获取handler对象
handler = urllib.request.HTTPHandler()
# 通过handler获取openr对象
opener = urllib.request.build_opener(handler)
# 调用open方法
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
代理服务器
代理服务器的常用功能?
1、突破自身IP访问限制
2、访问一些单位或团体内部资源
比如某大学FTP(前提是该代理地址在该资源的允许范围之内),使用教育网内地址免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询等共享服务。
3、提高放访问速度
通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户在访问相同信息时,则直接有缓冲区中取出信息,传给用户,以提高访问速度。
4、隐藏真实IP
上网者也可以通过这种方法隐藏自己的IP,免受攻击
代码的配置代理:
1、创建Request对象
2、创建ProxyHandler对象
3、用Handler对象创建openr对象
4、使用opener.open的函数发送请求
我们可以在快代理等平台,购买一个独享代理,这样来爬取数据,即使本机IP被封,我们依然可以使用代理IP来取访问某个网站,并爬取数据。
import urllib.request
url = "http://www.baidu.com/s?tn=25017023_13_dg&ch=1&ie=utf-8&wd=ip"
headers ={
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
request = urllib.request.Request(url, headers=headers)
proxies = {
"http":"106.227.10.176:16817"
}
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf-8')
f = open("daili.html", "w", encoding="utf-8")
f.write(content)
f.close()
即使我们使用了代理IP,但是如果我们在短时间内高频次的去访问某一个网站,也是避免不了被封的风险的!这个时候就需要代理池(有一堆高密的代理IP)。我们可以自己做一个简易粗糙的代理池:
proxies_pool = [
{
"http":"106.227.10.176:168171"
},
{
"http":"106.227.10.176:1681712"
},
{
"http":"106.227.10.176:16817123"
}
]
# 假设这些都是真实有效的独享IP,利用随机的特性,来实现简易的代理池
import random
proxies = random.choice(proxies_pool)
print(proxies) # 这样就能出现随机的代理
本次爬虫分享就到这里,如有错误,欢迎指正!感谢观看!