目录
一.爬虫介绍
1)相关概念
反爬机制
门户网站,可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取。
反反爬策略
爬虫程序可以通过制定相关的策略或者技术手段,破解门户网站中具备的反爬机制,从而可以获取门户网站中相关的数据。
robots.txt协议:
君子协议。规定了网站中哪些数据可以被爬虫爬取哪些数据不可以被爬取。
http协议
- 概念:就是服务器和客户端进行数据交互的一种形式。
常用请求头信息
- User-Agent:请求载体的身份标识
- Connection:请求完毕后,是断开连接还是保持连接
常用响应头信息
- Content-Type:服务器响应回客户端的数据类型
https协议:
- 安全的超文本传输协议
加密方式
- 对称秘钥加密
- 非对称秘钥加密
- 证书秘钥加密
2)HTTP请求
1.请求的网址 即URL 唯一确定的请求的资源
2.请求方法 get post
3.请求头
其中content-Type确定了post请求提交数据的方式
3)HTTP响应
1.响应状态码
200 服务器成功处理请求 返回数据成功,进行下一步
404 找不到请求的网页
2.响应头
Content-Type 返回内容的媒体类型
3.响应体 选择reponse选项 可显示响应体
4)json --dumps
json库的一些用法
方法 作用
json.dumps() 将python对象编码成Json字符串
json.loads() 将Json字符串解码成python对象
json.dump() 将python中的对象转化成json储存到文件中
json.load() 将文件中的json的格式转化成python对象提取出来
json.dump()和json.dumps()的区别
json.dumps() 是把python对象转换成json对象的一个过程,生成的是字符串。
json.dump() 是把python对象转换成json对象生成一个fp的文件流,和文件相关。
json参数
json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False, **kw)
obj:转化成json的对象。
sort_keys =True:是告诉编码器按照字典排序(a到z)输出。如果是字典类型的python对象,就把关键字按照字典排序。
indent:参数根据数据格式缩进显示,读起来更加清晰。
separators:是分隔符的意思,参数意思分别为不同dict项之间的分隔符和dict项内key和value之间的分隔符,把:和,后面的空格都除去了。
import json
x = {'name':'你猜','age':19,'city':'四川'}
#用dumps将python编码成json字符串
y = json.dumps(x)
print(y)
i = json.dumps(x,separators=(',',':'))
print(i)
# 输出结果
{"name": "\u4f60\u731c", "age": 19, "city": "\u56db\u5ddd"}
{"name":"\u4f60\u731c","age":19,"city":"\u56db\u5ddd"}
skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key 。
ensure_ascii=True:默认输出ASCLL码,如果把这个该成False,就可以输出中文。
check_circular:如果check_circular为false,则跳过对容器类型的循环引用检查,循环引用将导致溢出错误(或更糟的情况)。
allow_nan:如果allow_nan为假,则ValueError将序列化超出范围的浮点值(nan、inf、-inf),严格遵守JSON规范,而不是使用JavaScript等价值(nan、Infinity、-Infinity)。
default:default(obj)是一个函数,它应该返回一个可序列化的obj版本或引发类型错误。默认值只会引发类型错误。
######dump函数中只有一个fp参数与dumps不同
######fp:将obj序列化为JSON格式的流到fp (a.write()支持的类文件对象)。
二.request库
1.request模块的编码流程
1:指定url
--UA伪装
--请求参数的处理(没有的话可不加)
2:发起请求
3:获取响应数据
4:持久化存储
2.环境安装:
pip install requests
3.相关定义
1)请求方法
GET方法
POST方法
2) 传递URL参数
有时网站会通过URL来传递查询参数,这是可使用get或者post的params参数进行设置
3)定制请求头
在request中,get和post函数可以直接传递字典形式的User_Agent信息给headers参数实现定制请求头
3.相关案例
1)爬取搜狗首页的页面数据
import requests
if __name__ == "__main__":
#step_1:指定url
url = 'https://www.sogou.com/'
#step_2:发起请求
#get方法会返回一个响应对象
response = requests.get(url=url)
#step_3:获取响应数据.text返回的是字符串形式的响应数据
page_text = response.text
print(page_text)
#step_4:持久化存储
with open('./sogou.html','w',encoding='utf-8') as fp:
fp.write(page_text)
print('爬取数据结束!!!')
2)简易网页采集器
#网页采集器:(爬取搜狗指定词条的搜素界面)
#UA:user-agent(请求载体的身份标识)
#UA检测:门户网站的服务器会坚持对于请求的载体身份标识,如果检测到请求的载体身份标识为某一款----反爬策略
#浏览器,说明该请求是一个正常的请求,但是如果检测到请求的载体身份标识不是基于某一款浏览器
#的则表示为不正常的请求(爬虫),则服务器端就会拒绝该次请求
#UA伪装:让爬虫对应的请求载体身份标识伪装成某一款浏览器
import requests #下面一行如果搜索后url为https://www.sogou.com/web?query=lichuanlong
#UA伪装:将对应的user-Agent封装到某一个字典中
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"#定义一个请求头
}#可随机选取请求头,在网页界面f12寻找请求头
import requests #下面一行如果搜索后url为https://www.sogou.com/web?query=lichuanlong
url="https://www.sogou.com/web"#query是一个参数
#处理url携带的参数,封装到字典里
kw=input("enter a word:")
param={
"query":kw
}
#对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
response=requests.get(url=url,params=param,headers=headers)#get函数的参数
page_text=response.text
fileName=kw+".html"
with open (fileName,"w",encoding="utf-8") as fp:
fp.write(page_text)
print(fileName,"保存成功!!!")
3)豆瓣电影
import requests
import json
url="https://movie.douban.com/j/chart/top_list"
param={#这些属性可在f12的里面xhr 然后最后一行看见
'type': '5',
'interval_id': '100:90',
'action':'',
'start': '20',#从库中的第几个电影查取
'limit': '20', #一次取出的个数
}
headers={
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
response=requests.get(url=url,params=param,headers=headers)
list_data=response.json()
fp =open("douban。json","w",encoding='utf-8')
json.dump(list_data,fp=fp,ensure_ascii=False)
print('over')
#最后爬取的可取百度搜索json进行查看,点击格式化效验
4)破解百度翻译
import requests
import json
#1:指定url
post_url = "https://fanyi.baidu.com/sug"
#2:进行UA伪装
headers ={
"User=Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
关键字=input('输入一个关键字')
#3;post请求参数处理(同get请求一致)
data={
'kw': 关键字
}
#4请求发送
response=requests.post(url=post_url,data=data,headers=headers)
#5:获取响应数据:json()方法返回的是obj(如果确认响应数据是json 类型的,才可以使用json(),也可以继续使用text,但是得到的是字符串)
dic_obj=response.json()
#持久化存储
FileName=关键字+'.json'
fp=open(FileName,"w",encoding="utf-8")#fp参数:将obj序列化为JSON格式的流到fp (a.write()支持的类文件对象)。
json.dump(dic_obj,fp=fp,ensure_ascii=False)#dump与dumps中只有fp参数不一样
fp.close()#ensure_ascii=True:默认输出ASCLL码,如果把这个该成False,就可以输出中文。
print("over")
5)爬取京东我的购物车,每间隔一秒爬一次,共一百次,需要设置cookie信息.
import requests #导入requests模块
import time #导入time模块
headersvalue = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
'Cookie':'__jdu=1673555654;shshshfpa=565be4ca-07c2-cd67-78e4-92691c5c0e78-1590370825;shshshfpb=rVrKSmn2IcLo8w4GOV3s%2FvQ%3D%3D;unpl=V2_ZzNtbRAEREJxAUNcfEkLV2JQEl0RUkUUJQgTVnMdDgQzU0ZfclRCFnQUR1JnGFwUZwAZWEJcRhRFCEdkeBBVAWMDE1VGZxBFLV0CFSNGF1wjU00zQwBBQHcJFF0uSgwDYgcaDhFTQEJ2XBVQL0oMDDdRFAhyZ0AVRQhHZHseWgdjBxZaRlJzJXI4dmR5GFUDYTMTbUNnAUEpAE9ceR5VSGcEFF9GU0cScQ12VUsa;__jdv=76161171|baidu-pinzhuan|t_288551095_baidupinzhuan|cpc|0f3d30c8dba7459bb52f2eb5eba8ac7d_0_cb6f58496afc4b11b470a1d395c0eae3|1593578499694;areaId=1;ipLoc-djd=1-2800-0-0;PCSYCityID=CN_110000_110100_110108;user-key=a7ecfb5e-4ce5-45f3-bc50-f34f38529f35; __jda=122270672.1673555654.1590370824.1593575769.1593578500.5; __jdc=122270672;shshshfp=a361ce6062d6acb4a213e3fccb63cea4;cart-main=xx;cd=0;wlfstk_smdl=o0y1hhq7lhtt3bmuyyrsq4frzsm2x25l;TrackID=1bBtBpjzT4KptbszIfvAs3fgoavSXZLPO-rjd9P-eg3J0f2YgpvBSjdIiKW0synUQAkjr8iSOKnvciMPU3XkYwhLdym1pPC6JJlsY52WVqIk;thor=53783C64FD0A997288CB6CC2D828217654920A82353860FFBC08C3E814CD72E23EC5E6849607FB867D56BB6BB176E21719C7A0E6ED254BD9BEFAE84419AE8A5164F65661B13E6E9FE5D6D9A1543D1E5ED2933AA8FF5FBE38555C48D1EE365B4B2437708D39597BAF689B54B61F3E88115CFAB7D39814771A44D458655F67F6DE109AD4D41497D61F1BA892BB9B996453;pinId=fGixLn-KPTpnavPdRtFWag;pin=linglanwangyi; unick=%E5%87%8C-%E8%93%9D; ceshi3.com=000;_tp=12hoQaUhHWSC8herrlonvg%3D%3D;_pst=linglanwangyi;cn=4;3AB9D23F7A4B3C9B=PTX54LWTNEJQ2FVWJLZFXG7JIEW2QC7F7FN2Q4EQD2RWZ4HKYWOJ6WA3MFHDAPSX2SHQLN27F57I5BPG4U3L6YGVAY;shshshsID=8230af78e8b1a5f089e9e71304a10a50_7_1593578796165; __jdb=122270672.12.1673555654|5.1593578500'
} #设置请求头User-Agent和Cookie参数
url = 'https://cart.jd.com/cart.action' #定义url字符串
for i in range(1,100): #循环翻页
#异常处理
try:
#发送请求,并将返回结果赋值给r
r = requests.get(url, headers=headersvalue, timeout=1)
except requests.Timeout: #捕获Timeout异常
print('Timeout!') #输出“Timeout!”
else:
print(r.status_code) #输出返回状态码
print(r.text) #输出返回状态码
time.sleep(1) #设置1s休眠时间
6)药监总局
#(是一个动态加载数据
#首页中对应的企业信息数据是通过ajax动态请求来得到的
# 通过对详情页的url分析发现
# url的域名都是一样的,只有携带的参数(id)不一样
# id值可以从首页对应的ajax请求到的json串中获取
# 域名和id值拼接处一个一个完整的企业对应的详情页的url
# --详情页的企业详情数据也是动态加载出来的
# --观察后发现
# --所有的post请求的url都是一样的,只有参数id不一样
# 如果我们可以批量获取多家企业二id后,就可以将id和url形成一个完成的详情页对应详情)
import requests
import json
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
id_list=[]#存储企业的id
all_data_list=[]#存储所有的企业详情数据
#批量获取不同的企业的id值
url="http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList"
#参数的封装
for page in range(1,10):
data={
'on': 'true',
'page': '1',#页数可改变
'pageSize': '15',#可改一面你多少个
'productName': '',
'conditionType': '1',
'applyname': '',
'applysn': ''
}
json_ids=requests.post(url=url,params=data,headers=headers,).json()
for dic in json_ids["list"]:
id_list.append(dic["ID"])
#获取企业详情数据
post_url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
for id in id_list:
data={
"id":id
}
datail_json=requests.post(url=post_url,data=data,headers=headers).json()
all_data_list.append(datail_json)
#持久化存储
fp=open("alldata.json","w",encoding="utf-8")
json.dump(all_data_list,fp=fp,ensure_ascii=False)
print("over!!!")
7)获取二进制文件如一张图
import requests
r=requests.get('https://img9.doubanio.com/view/subject/s/public/s33643895.jpg')
print(r.content)#content返回的是二进制形式的图片数据
print(r.text)
with open ('fengmian.jpg','wb') as f :
f.write(r.content)
三 数据解析
1 原理
聚焦爬虫:爬取页面中指定的页面内容。
- 编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
数据解析分类:
- 正则
- bs4
- xpath(***)
数据解析原理概述:
- 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储
- 1.进行指定标签的定位
- 2.标签或者标签对应的属性中存储的数据值进行提取(解析)
正则解析:
<div class="thumb">
<a href="/article/121721100" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12172/121721100/medium/DNXDX9TZ8SDU6OK2.jpg" alt="指引我有前进的方向">
</a>
</div>
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
bs4进行数据解析
- 数据解析的原理:
- 1.标签定位
- 2.提取标签、标签属性中存储的数据值
- bs4数据解析的原理:
- 1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
- 环境安装:
- pip install bs4
- pip install lxml
- 如何实例化BeautifulSoup对象:
- from bs4 import BeautifulSoup
- 对象的实例化:
- 1.将本地的html文档中的数据加载到该对象中
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
- 2.将互联网上获取的页面源码加载到该对象中
page_text = response.text
soup = BeatifulSoup(page_text,'lxml')
- 提供的用于数据解析的方法和属性:
- soup.tagName:返回的是文档中第一次出现的tagName对应的标签
- soup.find():
- find('tagName'):等同于soup.div
- 属性定位:
-soup.find('div',class_/id/attr='song')
- soup.find_all('tagName'):返回符合要求的所有标签(列表)
- select:
- select('某种选择器(id,class,标签...选择器)'),返回的是一个列表。
- 层级选择器:
- soup.select('.tang > ul > li > a'):>表示的是一个层级
- oup.select('.tang > ul a'):空格表示的多个层级
- 获取标签之间的文本数据:
- soup.a.text/string/get_text()
- text/get_text():可以获取某一个标签中所有的文本内容
- string:只可以获取该标签下面直系的文本内容
- 获取标签中属性值:
- soup.a['href']
xpath解析
:最常用且最便捷高效的一种解析方式。通用性。
xpath可以复制,f12后选择所要定位的那个标签,鼠标右击 显示复制,选择复制xpath即可
- xpath解析原理:
- 1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
- 环境的安装:
- pip install lxml
- 如何实例化一个etree对象:from lxml import etree
- 1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
- 2.可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text')
- xpath('xpath表达式')
- xpath表达式:
- /:表示的是从根节点开始定位。表示的是一个层级。
- //:表示的是多个层级。可以表示从任意位置开始定位。
- 属性定位://div[@class='song'] tag[@attrName="attrValue"]
- 索引定位://div[@class="song"]/p[3] 索引是从1开始的。
- 取文本:
- /text() 获取的是标签中直系的文本内容
- //text() 标签中非直系的文本内容(所有的文本内容)
- 取属性:
/@attrName ==>img/src
2)相关案例
1 )正则解析案例一:爬取百度搜索页面的数据
import requests
import re
url = "https://www.baiud.com/"
headersvalue={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
r=requests.get(url,headers=headersvalue)
html=r.text
#使用re模块的search函数查询星纹对应的节点
item=re.search('<div.*?s-top-left.*?a.*href="(.*?)".*?>(.*?)</a>',html,re.S)#re。s撇皮包括换行符的所有字符
print(item.group(1),item.group(2))#输出节点的属性和文本
#search()方法返回match对象,他的group()方法可以返回match对象的一个或多个子组,而group(1)为第一个子组值
正则案例二(1):糗图爬取
import requests
import re
import os
#创建一个文件夹,保存所有的图片
if not os.path.exists("./qiutulibs"):
os.mkdir("./qiutulibs")
url="https://www.qiushibaike.com/imgrank/"
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
#使用通用爬虫对 url对应的一整张页面进行抓取
page_text=requests.get(url=url,headers=headers).text
#使用聚焦爬虫将页面的所有糗图进行解析提取
ex ='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list=re.findall(ex,page_text,re.S)
for src in img_src_list:
#拼接出一个完整的图片url
src="https:"+src
#请求到了图片的二进制数据
img_data=requests.get(url=src,headers=headers).content
#生成图片名称
img_name=src.split('/')[-1]
#图片存储的路径
imgPath="./qiutulibs/"+img_name
with open(imgPath,'wb')as fp:
fp.write(img_data)
print(img_name,"下载完成!!!")
正则案例二(1):糗图爬取
import requests
import re
import os
#创建一个文件夹,保存所有的图片
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
#如果这个文件夹不存在就创建一个
if not os.path.exists("./qiutulibs"):
os.mkdir("./qiutulibs")
#设置一个通用的url模板
url="https://www.qiushibaike.com/imgrank/page/%d/"
#pageNum=2
n=int(input("输入需要的页数"))
for pageNum in range(1,n+1):
#对应页面的url
new_url=format(url%pageNum)
#使用通用爬虫对 url对应的一整张页面进行抓取
page_text=requests.get(url=new_url,headers=headers).text
#使用聚焦爬虫将页面的所有糗图进行解析提取
ex ='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list=re.findall(ex,page_text,re.S)
for src in img_src_list:
#拼接出一个完整的图片url
src="https:"+src
#请求到了图片的二进制数据
img_data=requests.get(url=src,headers=headers).content
#生成图片名称
img_name=src.split('/')[-1]
#图片存储的路径
imgPath="./qiutulibs/"+img_name
with open(imgPath,'wb')as fp:
fp.write(img_data)
print(img_name,"下载完成!!!")
2)数据解析-bs4
示例一;爬取三国演义章节标题和内容
import requests
from bs4 import BeautifulSoup
import lxml
#对手首页页面进行爬取
headers={
"Suer-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62"
}
url="https://www.shicimingju.com/book/sanguoyanyi.html"
page_text=requests.get(url,headers).text.encode("ISO-8859-1")
#在首页解析出章节标题和详情页的url
soup=BeautifulSoup(page_text,"lxml")
#解析章节标题和详情页的url
li_list=soup.select(".book-mulu>ul>li")
fp=open("./sanguo.txt","w",encoding="utf-8")
for li in li_list:
title=li.a.string
datail_url="https://www.shicimingju.com/"+li.a["href"]#得到的域名不完全
#对详情页发起请求,解析出章节内容
datail_page_text=requests.get(url=datail_url,headers=headers).content
datail_soup=BeautifulSoup(datail_page_text,"lxml")
div_tag=datail_soup.find("div",class_="chapter_content")
#解析到了章节的内容
content=div_tag.text
fp.write(title+":"+content+"\n")
print(title,"爬取成功!!!")
3)xpath解析
示例一:58二手房.py
import requests
from lxml import etree
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
#爬取页面相关数据
url="https://www.58.com/ershoufang/"
page_text=requests.get(url,headers).text
#数据解析
tree=etree.HTML(page_text)
#存储的就是li标签
td_list=tree.xpath('//*[@id="global"]/table/tr')
fp=open("58.txt","w",encoding="utf-8")
for tr in td_list:
#局部解析
title=tr.xpath("./td[2]/a/text()")[0]#./代表站点根目录,../代表当前目录的上一级目。
print(title)
fp.write(title+"\n")
fp.close()
示例二:4k图片解析
import requests
from lxml import etree
import os
url = 'http://pic.netbian.com/4kmeinv/'
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
#不这样搞会乱码
response = requests.get(url=url,headers=headers)
#手动设定响应数据的编码格式
#普通的乱码可以这样搞,但这个不行,考虑换另一种方式
# response.encoding = 'utf-8'
page_text = response.text
#数据解析:src的属性值 alt属性
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
#创建一个文件夹
if not os.path.exists('./picLibs'):
os.mkdir('./picLibs')
for li in li_list:
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/img/@alt')[0]+'.jpg'
#通用处理中文乱码的解决方案
img_name = img_name.encode('iso-8859-1').decode('gbk')
# print(img_name,img_src)
#请求图片进行持久化存储
img_data = requests.get(url=img_src,headers=headers).content
img_path = 'picLibs/'+img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')
fp.close()
#通用处理中文乱码的解决方案 img_name = img_name.encode('iso-8859-1').decode('gbk')
示例三:全国城市名称爬取
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
from lxml import etree
#项目需求:解析出所有城市名称https://www.aqistudy.cn/historydata/
if __name__ == "__main__":
# headers = {
# 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
# }
# url = 'https://www.aqistudy.cn/historydata/'
# page_text = requests.get(url=url,headers=headers).text
#
# tree = etree.HTML(page_text)
# host_li_list = tree.xpath('//div[@class="bottom"]/ul/li')
# all_city_names = []
# #解析到了热门城市的城市名称
# for li in host_li_list:
# hot_city_name = li.xpath('./a/text()')[0]
# all_city_names.append(hot_city_name)
#
# #解析的是全部城市的名称
# city_names_list = tree.xpath('//div[@class="bottom"]/ul/div[2]/li')
# for li in city_names_list:
# city_name = li.xpath('./a/text()')[0]
# all_city_names.append(city_name)
#
# print(all_city_names,len(all_city_names))
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
#解析到热门城市和所有城市对应的a标签
# //div[@class="bottom"]/ul/li/ 热门城市a标签的层级关系
# //div[@class="bottom"]/ul/div[2]/li/a 全部城市a标签的层级关系
a_list = tree.xpath('//div[@class="bottom"]/ul/li/a | //div[@class="bottom"]/ul/div[2]/li/a')
all_city_names = []
for a in a_list:
city_name = a.xpath('./text()')[0]
all_city_names.append(city_name)
print(all_city_names,len(all_city_names))
五 反爬虫策略
1)反爬虫策略
1 通过headers反爬虫
2 基于用户行为反爬虫 如 同意IP短时间访问多次
3 采用动态加载数据反爬虫
2)应对反爬虫
1 使用代理IP
request库实现使用代理IP非常方便,只需要构造一个代理IP的字典,然后在发送HTTP请求时使用proxies参数添加代理IP的字典即可,如果需要使用多个代理IP,就写成列表包含字典
相关案例:
import requests
url='https://www.pythontab.com'
proxies=[
{'http':'http://121.232.148.167:9000'},
{'http':'http://39.105.28.28:8188'}
]
for proxy in proxies:
try: #设置代理IP
r=requests.get(url=url,proxies=proxy)
except:
#请求错误,输出验证结果《此代理IP不可用》
print('此代理IP不可用')
else:
print("此代理IP可用",proxy)
print('响应状态码',r.status_code)
2 降低请求频率
运行爬虫程序时,可以设置两次请求i之间的世纪那间隔来降低请求频率(通过time库设置程序秀米那时间来实现)若设为固定数字,会被当作不正常用户,可以用random‘库
案例:
import requests
import random
import time
url='https://www.pythontab.com'
for i in range(1,10):
t1=time.time()#获取当前时间
r=requests.get(url)
#设置随机休眠时间
sleep_time=random.randint(0,2)+random.random()
time.sleep(sleep_time)#程序休眠
t2=time.time()
print('两次时间间隔',t2-t1)
3 分析请求页面
4 selenium模拟浏览器