1.
如果我们把互联网比作一个大蜘蛛网,计算机上的数据是蜘蛛网上的猎物,爬虫程序是一个小蜘蛛网
蜘蛛,沿着蜘蛛网抓取你想要的数据
解释1:根据一个程序Url(http://www.taobao.com)爬网页,获取有用的信息 解释2:使用程序模拟浏览器,向服务器发送请求,获取响应信息
2. 爬虫核心?
-
爬网页:爬整个网页 它包含了网页中的所有内容
-
分析数据:在网页上获取数据 进行解析
-
难点:爬虫和反爬虫之间的博弈
3. 爬虫的用途?
-
数据分析/人工数据集
-
冷启动社交软件
-
舆情监控
-
监控竞争对手
4.
通用爬虫: 实例 百度、360、google、sougou等搜索引擎‐‐‐伯乐在线 功能 访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务 robots协议 一个常见的协议,添加robots.txt文件说明本网站不能抓取哪些内容,不能起到限制作用 自己写的 爬虫不需要遵守 网站排名(SEO) 1. 根据pagerank算法值进行排名(参考个网站流量、点击率等指标) 2. 百度竞价排名 缺点 1. 抓取的数据大多是无用的 2.无法根据用户的需求准确获取数据
聚焦爬虫 功能 爬虫程序根据需要实现,抓取所需数据 设计思路 1.确定要爬的东西url 如何获取Url 2.通过模拟浏览器http协议访问url,获取服务器返回html代码 如何访问 3.解析html字符串(按规则提取所需数据) 如何解析
5. 反爬手段
-
User‐Agent:
- User Agent中文名称为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版 本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
-
代理IP:
- 西次代理
- 快代理
- 什么是高匿名、匿名和透明代理?它们有什么区别?
- 使用透明代理,对方的服务器可以知道你使用了代理,也知道你的真实性IP。
- 使用匿名代理,对方个服务器可以知道你使用了代理,但不知道你的真相IP。
- 使用高匿名代理,对方的服务器不知道你使用了代理,更不用说你的真实性了IP。
-
验证码访问
-
打码平台
-
云打码平台
-
超级??
-
-
-
动态加载网页 网站返回js数据 不是网页的真实数据
- selenium驱动真实浏览器发送请求
-
数据加密
- 分析js代码
6. urllib库使用
urllib.request.urlopen()
模拟浏览器向服务器发送请求
response
服务器返回的数据
-
response数据类型是
HttpResponse
-
字节‐‐>字符串 解码decode
-
字符串‐‐>字节 编码encode
-
read()
读取字节形式的二进制 扩展:rede(5)返回前几个字节 -
readline()
读取一行 -
readlines()
一行一行读取 直至结束 -
getcode()
获取状态码 -
geturl()
获取url -
getheaders()
获取headers -
urllib.request.urlretrieve()
- 请求网页
- 请求图片
- 请求视频
爬百度首页源码:
# 使用urllib获取百度首页源码 import urllib.request # 定义一个url url = 'http://www.baidu.com' # 模拟浏览器向服务器发送请求 response = urllib.request.urlopen(url) # 在响应中获取页面源码 # read方法是以字节形式返回二进制数据 # 将二进制数据转换为字符串 # 二进制 =》字符串 解码 decode页面上的编码格式(编码格式)head
标签meta的charset属性 content = response.read().decode('utf-8') print(content)
import urllib.request
url = 'http://www.baidu.com'
response = urllib.request.urlopen(url)
# response 是HTTPResponse类型
# print(type(response))
# 按照一个字节一个字节的去读
# content = response.read()
# 读取一行
# content = response.readline()
# content = response.readlines()
# 返回状态码,如果是200,就证明证明没有错
# print(response.getcode())
# 返回访问的url地址
# print(response.geturl())
# 获取的是一些状态信息
print(response.getheaders())
import urllib.request
# 下载一个网页
# url_page = 'http://www.baidu.com'
# urllib.request.urlretrieve(url_page, 'baidu.html')
# 下载图片
# url_img = 'https://img-home.csdnimg.cn/images/20201124032511.png'
# urllib.request.urlretrieve(url=url_img, filename='csdn.jpg')
# 下载视频
url_video = 'https://vd2.bdstatic.com/mda-jmsy151cd1ijyz3r/hd/mda-jmsy151cd1ijyz3r.mp4?v_from_s=hkapp-haokan-hnb&auth_key=1656516999-0-0-1fcd521c8a93ff8141ca1645aa7c315c&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=0398986023&vid=3985750168738470460&abtest=102784_2-102836_3-102982_3-3000232_2&klogid=0398986023'
urllib.request.urlretrieve(url_video, 'test.mp4')
7.
UA介绍:User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等
语法:
import urllib.request
url = 'https://www.baidu.com'
# headers详情见下边图片
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
# 因为参数顺序的问题,需要关键字传参
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号, 这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。 但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突, 所以,中国制定了GB2312编码,用来把中文编进去。 你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc‐kr里, 各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。 因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。 Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。 现代操作系统和大多数编程语言都直接支持Unicode。
8.
1.get请求方式:urllib.parse.quote()
import urllib.request
import urllib.parse
url = 'https://www.baidu.com/s?wd='
# 把参数转为ASCII编码
url += url + urllib.parse.quote('周杰伦')
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
2.
import urllib.request
import urllib.parse
url = 'https://www.baidu.com/s?'
# 利用字典类型编码传参
data = {
'wd': '蔡依林',
'sex': '女'
}
url += urllib.parse.urlencode(data)
print(url)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
3.post请求方式
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/103.0.0.0 Safari/537.36'
}
data = {
'kw': 'hello'
}
# post请求的参数必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
# post请求的参数要放在请求对象定制的参数中
request = urllib.request.Request(url=url, data=data, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
# 字符串转为json对象
obj = json.loads(content)
print(obj)
-
get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法
-
post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法
import urllib.request
import urllib.parse
import json
url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'
# 浏览器控制台查看header
headers = {
'Cookie': 'BIDUPSID=3223FE11042DAD864DA852D876FDDFA9; PSTM=1654091563; BAIDUID=3223FE11042DAD86DD7C657D63E1E52C:FG=1; APPGUIDE_10_0_2=1; SOUND_PREFER_SWITCH=1; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1; FANYI_WORD_SWITCH=1; SOUND_SPD_SWITCH=1; BDUSS=HExR09IbHgtdi1ibEtmblo2MVdRdHdyelc5UGk3Q1MyYk1mWUZJQW9pWEtCYjlpRVFBQUFBJCQAAAAAAAAAAAEAAAABrg80x-O-~dK7ysDI4cfp2LwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMp4l2LKeJdiM; BDUSS_BFESS=HExR09IbHgtdi1ibEtmblo2MVdRdHdyelc5UGk3Q1MyYk1mWUZJQW9pWEtCYjlpRVFBQUFBJCQAAAAAAAAAAAEAAAABrg80x-O-~dK7ysDI4cfp2LwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMp4l2LKeJdiM; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; delPer=0; PSINO=1; H_PS_PSSID=36545_36722_36454_31253_36663_36413_36691_36167_36693_36698_36075_36744_26350_36685_36469; BA_HECTOR=2081850k2l24ag24011hbrb0l14; ZFY=eQSkt9DtBzoEZ2DdNJW5f:BgPs:BesKMBKOGsMVfN7H5c:C; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1654092726,1656597526; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1656597526; ab_sr=1.0.1_ZjlmNzdiNWNjYTIwYTY4NTcxNGY3NDk3NjE1NGY3YmZlNTdjMjdiMzhkYjJiZWE3ZjcyOGI0NGMwNjZkYWU1YzgyMmQzMjU0ZjQ2NjBhMzI0ZTVlMDk2MjZiMjAzMDE5ZjQ2NTA0ODNlYWQ2NjEzMTk5ZWRhMmZkZTE2NWJmZDc1MDkyNDQxNTUwMzk1YjczOTdiNDUxYTJkMjlkZDA1ZmM1MzVkNWIzYjJkYWQ2Y2Q5ZmNiODk5MWZkNzBkYjUz'
}
data = {
'from': 'en',
'to': 'zh',
'query': 'hello',
'transtype': 'realtime',
'simple_means_flag': '3',
'sign': '54706.276099',
'token': '406f9ef9798def66b41a2d8f61f5c96a',
'domain': 'common'
}
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url, data=data, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
obj = json.loads(content)
print(obj)
# python对象转换为json字符串 ensure_ascii=False 忽略字符集编码
s = json.dumps(obj,ensure_ascii=False)
print(s)
9. ajax的get请求
import urllib.request
url = 'https://movie.douban.com/j/chart/top_list?type=24&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/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
# 将内容保存在文件中
# open默认使用gbk编码,如果想保存汉字,指定编码格式为utf-8
# fp = open('douban.json', 'w', encoding='utf-8')
# fp.write(content)
# fp.close()
# 另一种写法
with open('douban1.json','w', encoding='utf-8') as fp:
fp.write(content)
import urllib.request
import urllib.parse
# 创建定制请求
def create_request(page):
url = 'https://movie.douban.com/j/chart/top_list?type=24&interval_id=100%3A90&action=&'
# 计算当前页数据的起始和终止条数
start = (page - 1) * 20
limit = 20
data = {
'start': start,
'limit': limit
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
url += urllib.parse.urlencode(data)
request = urllib.request.Request(url=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(content, page):
with open('douban_' + str(page) + '.json', 'w', encoding='utf-8') as fp:
fp.write(content)
fp.close()
# 程序的入口,写不写都可以
if __name__ == '__main__':
start_page = 1
end_page = int(input("请输入页数:"))
for i in range(start_page, end_page + 1):
request = create_request(i)
content = get_content(request)
down_load(content, i)
10. ajax的post请求
import urllib.request
import urllib.parse
# 定制请求
def create_request(page):
url = 'http://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/103.0.0.0 Safari/537.36'
}
data = {
'cname': '北京',
'pid': '',
'pageIndex': page,
'pageSize': 10,
}
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url, headers=headers, data=data)
return request
# 获取请求内容
def get_content(request):
response = urllib.request.urlopen(request)
return response.read().decode('utf-8')
# 将内容写入到本地文件
def down_load(page, content):
with open('KFC_' + str(page) + '.json', 'w', encoding='utf-8') as f:
f.write(content)
f.close()
if __name__ == '__main__':
start_page = 1
end_page = int(input('请输入页数:'))
for i in range(start_page, end_page + 1):
request = create_request(i)
content = get_content(request)
down_load(i, content)
11.
-
HTTPError
类是URLError
类的子类 -
导入的包
urllib.error.HTTPError urllib.error.URLError
-
http
错误:http
错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。 -
通过
urllib
发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try‐
except
进行捕获异常,异常有两类,URLError
\HTTPError
import urllib.request
import urllib.error
url = 'https://blog.csdn.net/weixin_43847283/article/details/1255564151'
# url = "http://adad121a.com"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
try:
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
print(response)
content = response.read().decode('utf-8')
except urllib.error.HTTPError:
print("地址错误")
except urllib.error.URLError:
print("地址错误")
12.
有些网站会把cookie
放入header
去请求,cookie
存放的是登录之后的信息。请求的时候必须带上cookie
才可以请求
13.Handler处理器
-
urllib.request.urlopen(url)
- 不能定制请求头
-
urllib.request.Request(url,headers,data)
- 可以定制请求头
-
Handler
- 定制更高级的请求头(随着业务逻辑的复杂 请求对象的定制已经满足不了我们的需求(动态cookie和代理不能使用请求对象的定制)
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/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
# 获取headler对象
handler = urllib.request.HTTPHandler()
# 获取opener对象
opener = urllib.request.build_opener(handler)
#调用open方法
response = opener.open(request)
print(response.read().decode('utf‐8'))
14.
-
代理的常用功能?
-
突破自身IP访问限制,访问国外站点。
-
访问一些单位或团体内部资源
- 扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
-
提高访问速度
- 扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
-
隐藏真实IP
- 扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。
-
2.代码配置代理
-
创建
Reuqest
对象 -
创建
ProxyHandler
对象 -
用
handler
对象创建opener
对象 -
使用
opener.open
函数发送请求
import urllib.request
import random
url = 'http://www.baidu.com/s?wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
# 定义一个代理池
proxies = [{
"http": "127.0.0.1:1"}, {
"http": "127.0.0.1:2"}]
# 随机取出一个代理ip
proxie = random.choice(proxies)
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf‐8')
print(content)
with open('dl.html', 'w', encoding='utf‐8')as fp:
fp.write(content)