一.Urllib
1.什么是互联网爬虫?
如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的数据
解释1:通过一个程序,根据Url(http://www.taobao.com)进行爬取网页,获取有用信息 解释2:使用程序模拟浏览器,去向服务器发送请求,获取响应信息
2.爬虫核心?
1.爬取网页:爬取整个网页 包含了网页中所有得内容 2.解析数据:将网页中你得到的数据 进行解析 3.难点:爬虫和反爬虫之间的博弈
3.爬虫的用途?
- 数据分析/人工数据集
- 社交软件冷启动
- 舆情监控
- 竞争对手监控
4.爬虫分类?
通用爬虫:
实例
百度、360、google、sougou等搜索引擎‐‐‐伯乐在线
功能
访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务
robots协议
一个约定俗成的协议,添加robots.txt文件,来说明本网站哪些内容不可以被抓取,起不到限制作用自己写的爬虫无需遵守
网站排名(SEO)
1. 根据pagerank算法值进行排名(参考个网站流量、点击率等指标)
2. 百度竞价排名
缺点
1. 抓取的数据大多是无用的
2.不能根据用户的需求来精准获取数据
聚焦爬虫
功能
根据需求,实现爬虫程序,抓取需要的数据
设计思路
1.确定要爬取的url
如何获取Url
2.模拟浏览器通过http协议访问url,获取服务器返回的html代码
如何访问
3.解析html字符串(根据一定规则提取需要的数据)
如何解析
5.反爬手段?
1.User‐Agent:
User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
2.代理IP
西次代理
快代理
什么是高匿名、匿名和透明代理?它们有什么区别?
1.使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP。
2.使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP。
3.使用高匿名代理,对方服务器不知道你使用了代理,更不知道你的真实IP。
3.验证码访问
打码平台
云打码平台
超级🦅
4.动态加载网页 网站返回的是js数据 并不是网页的真实数据
selenium驱动真实的浏览器发送请求
5.数据加密
分析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 = 'http://www.baidu.com'
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
print(content)
例: urllib 一个类型和6个方法
import urllib.request
url = 'http://wwww.baidu.com'
response = urllib.request.urlopen(url)
print(response.getcode())
print(response.geturl())
print(response.getheaders())
例: urllib 下载视频图片音乐
import urllib.request
url_video = "https://vd2.bdstatic.com/mda-kcg9f303imrgda6v/mda-kcg9f303imrgda6v.mp4"
urllib.request.urlretrieve(url_video,"dowload/template/视频_055.mp4")
7.请求对象的定制
UA介绍:User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等 语法:request = urllib.request.Request()
例:请求对象的定制
import urllib.request
url = 'https://www.baidu.com '
henders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url=url,headers = henders)
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?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd='
header= {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
name = urllib.parse.quote('周杰伦')
url += name
request = urllib.request.Request(url=url,headers=header)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
2.get请求方式:urllib.parse.urlencode()
import urllib.request
import urllib.parse
bese_url = 'https://www.baidu.com/s?'
data ={
'wd': '周杰伦',
}
new_data = urllib.parse.urlencode(data)
url = bese_url+new_data
header= {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
print(url)
request = urllib.request.Request(url= url, headers =header)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
3.post请求方式
import urllib.request
import urllib.parse
url ='https://fanyi.baidu.com/sug'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
data= {
'kw': '美女',
}
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')
import json
print(json.loads(content))
'''
总结:
post请求方式的参数必须编码: data = urllib.parse.urlencode(data)
编码之后 必须调用encode 方法 urllib.parse.urlencode(data).encode('utf-8')
参数是放在请求对象定制的方法中的,request = urllib.request.Request(url=url,data=data,headers=headers)
'''
总结:post和get区别?
1:get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法 2:post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法
案例练习:百度详细翻译
import urllib.request
import urllib.parse
import json
url = 'https://fanyi.baidu.com/v2transapi?from=zh&to=en'
headers = {
'Cookie': 'BIDUPSID=F16CB27ACF03F17C663329DE31E4062A; PSTM=1636886727; __yjs_duid=1_55c745398f06267e3638446ca7d77d7f1636887396137; BAIDUID=6DEE7240C943288B149F4CCB41CDA797:FG=1; H_BDCLCKID_SF_BFESS=tJAqoD05JD83H48k-4QEbbQH-UnLqhQg0mOZ04n-ah02V4O9jU8hb6F_qJjCL6kHW20j0h7m3UTKsq76Wh35K5tTQP6rLtbbQJR4KKJxbnLWKtbaMPKhQfDThUJiB5OLBan7-RvIXKohJh7FM4tW3J0ZyxomtfQxtNRJ0DnjtpChbC_Rj6KbjT5yeU5eetjK2CntsJOOaCvEOt5Oy4oWK441Db5ehTbRJCcPoT6C0xKWhlvoD-Jc3M04K4o9-hvT-54e2p3FBUQJeMLxQft20b0Ee2cJL4naJmTG2n7jWhk2Dq72yhoOQlRX5q79atTMfNTJ-qcH0KQpsIJM5-DWbT8IjHCeJ6KfJJ4DoIv5b-0_HRT1Mt5Eh-cH-UnLqMtf3eOZ0l8Ktq0KMRbvjx8hblbLqJjCL6ktaeJRQnOmWIQHDUnh54j1QqtRetraQjFeJer4KKJx2PPWeIJo5t5n2h_phUJiB5OLBan7-RvIXKohJh7FM4tW3J0ZyxomtfQxtNRJ0DnjtnLhbRO4-TFKjj3Bjf5; MCITY=-131%3A; RT="z=1&dm=baidu.com&si=f5wjv2hczvs&ss=l1g7dmgn&sl=6&tt=3lh&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=elh&ul=gg8&hd=ghu"; BDRCVFR[S4-dAuiWMmn]=FZ_Jfs2436CUAqWmykCULPYrWm1n1fz; delPer=0; PSINO=2; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; H_PS_PSSID=; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; BA_HECTOR=05a0ak24ah0ga52gs81h4lho20q; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1649067782; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1649067782; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; APPGUIDE_10_0_2=1; ab_sr=1.0.1_NGIwOGNmYzEyZjdjYjMxZjI3ZjBlYjIzZmNjZTE1ZWRkZWY1N2ViMThjODVjNGRkZDZmMGViNTQxNDQ2MzVlMmMwY2Q1MzE0ZjYyMDA3MzgwNjAzYmI1MjgxYWExNWVjZDY2NzZmOTc2NzU1NjJjYzkxNTY3NmUxZjE1NDVjNTZkOTJhZDhjMThmY2Y1NThjZjViZTNhMDkwYzViN2EzMw==',
}
data = {
'from': 'zh',
'to': 'en',
'query': '美女',
'transtype': 'translang',
'simple_means_flag': 3,
'sign': 551517.821612,
'token': 'fcb141eb5cc8b83af203e132e27bcb76',
'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')
result = json.loads(content)
print(result)
9.ajax的get请求
案例:豆瓣电影 获取豆瓣电影第一页的数据并且保存起来
import urllib.request
import json
headers ={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
url = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&tart=0"
request = urllib.request.Request(url = url,headers= headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
with open("dowload/template/douban.json",'w',encoding='utf-8') as fp:
fp.write(content)
爬取豆瓣电影前10页数据
'''
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend
# &page_limit=20&page_start=0
#https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend
# &page_limit=20&page_start=20
# https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend
# &page_limit=20&page_start=40
# https://movie.douban.com/j/search_subjects?
# type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=60
通过上面的地址分析 页数和page_start的参数有关系.只要更改page_start的参数,就可以获取对应页数的值
page 1 2 3 4
page_start 0 20 40 60
# 规律: page_start = (page-1)*20
'''
import urllib.parse
import urllib.request
def create_request(page):
base_url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&'
data = {
'page_start': (page-1) *20,
'page_limit': 20
}
url = base_url + urllib.parse.urlencode(data)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
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(page,content):
with open("dowload/template/豆瓣_" +str(page)+ '_062.json', 'w',encoding='utf-8') as fp:
fp.write(content)
if __name__ == '__main__':
start_page = int(input('请输入起始的页码'))
end_page = int(input('请输入结束的页码'))
for page in range(start_page,end_page+1):
print(page)
request = create_request(page)
content = get_content(request)
down_load(page,content)
10.ajax的post请求
案例:KFC官网
'''
第一页
http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
cname: 北京
pid:
pageIndex: 1
pageSize: 10
第二页
http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
cname: 北京
pid:
pageIndex: 2
pageSize: 10
'''
import urllib.request
import urllib.parse
def create_request(page):
beas_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
'cname': '北京',
'pid': '',
'pageIndex': page,
'pageSize': 10
}
data= urllib.parse.urlencode(data).encode('utf-8')
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url = beas_url,data = data ,headers=headers)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def dow_load(page,content):
with open('dowload/template/kfc_' +str(page) + '_063.json','w',encoding='utf_8') as fp:
fp.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)
dow_load(page,content)
11.URLError\HTTPError
简介:1.HTTPError类是URLError类的子类
2.导入的包urllib.error.HTTPError urllib.error.URLError
3.http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出
了问题。
4.通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try‐
except进行捕获异常,异常有两类,URLError\HTTPError
import urllib.request
import urllib.error
url = 'https://blog.csdn1.net/nav/algo'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
try:
request = urllib.request.Request(url = url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
except urllib.error.HTTPError:
print("系统升级中")
except urllib.error.URLError:
print("地址异常")
12.cookie登录
使用案例: 1.微博的cookie登陆
import urllib.request
url = 'https://weibo.com/u/7751984183/home'
headers = {
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 'wb_view_log=1920*10801; SINAGLOBAL=9641210644196.078.1649142571515; XSRF-TOKEN=dIWOhbeDSacC_EreXg3LMydm; login_sid_t=2c3ccd62daf4320f5ff9d51da6e2c2d9; cross_origin_proto=SSL; _s_tentry=weibo.com; Apache=2376798542625.207.1649144256355; ULV=1649144256365:2:2:2:2376798542625.207.1649144256355:1649142571530; ALF=1680680282; SSOLoginState=1649144283; SUB=_2A25PT4GLDeRhGeFJ7lMY-CrNwz-IHXVsPPRDrDV8PUNbmtAKLUn1kW9Nf6CP4Ch17BiqiXZmi0tUUj0G2yzvwTbH; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WW8eBuaUnrgjrzqHBfbLsDQ5JpX5KzhUgL.FoMNSK241hBp1he2dJLoI7RLxKBLB.BL1KH-eK.4SBtt; WBPSESS=Dt2hbAUaXfkVprjyrAZT_IAPcorLTGRl5QDle__skOlcblCUgTS-NPPrg_XMjHZHApxch19UI0usNBauurkCp4diMcajdDUtYlhBp2r27yDIkpjlJUHrnOGWpW5ZL6fIO37hGDI_olJHFExrExs5Zff2PnyEnvEbGC8ILlv4KeMC-6wHFFyyBFUrZZL0nHr5FfkjG8Avvx3Bv3NqeZWrV2w==',
'referer': 'https://weibo.com/',
'traceparent': '00-7111dd4343961846623239e6adc59855-f41338966fbb8dc9-00',
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
'x-requested-with': 'XMLHttpRequest',
'x-xsrf-token': 'dIWOhbeDSacC_EreXg3LMydm'
}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
with open('dowload/template/微博_065.html','w',encoding='utf-8') as fp:
fp.write(content)
13.Handler处理器
为什么要学习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; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
handler = urllib.request.HTTPHandler
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
14.代理服务器
1.代理的常用功能?
1.突破自身IP访问限制,访问国外站点。
2.访问一些单位或团体内部资源
扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务
器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
3.提高访问速度
扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲
区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
4.隐藏真实IP
扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。
2.代码配置代理
创建Reuqest对象
创建ProxyHandler对象
用handler对象创建opener对象
使用opener.open函数发送请求
import urllib.request
url = 'http://www.baidu.com/s?wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
proxies = {
'http': '47.113.90.161:83',
}
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
扩展:1.代理池
proxies_pool = [
{'http': '47.113.90.161:83'},
{"http": '202.55.5.209:8090'}
]
import random
import urllib.request
proxies = random.choice(proxies_pool)
print(proxies)
url = 'http://www.baidu.con=m?wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
header = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(header)
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
二. XPATH
1.xpath
xpath使用: 注意:提前安装xpath插件 (1)打开chrome浏览器 (2)点击右上角小圆点 (3)更多工具 (4)扩展程序 (5)拖拽xpath插件到扩展程序中 (6)如果crx文件失效,需要将后缀修改zip (7)再次拖拽 (8)关闭浏览器重新打开 (9)ctrl + shift + x (10)出现小黑框 1.安装lxml库 pip install lxml ‐i https://pypi.douban.com/simple 2.导入lxml.etree from lxml import etree 3.etree.parse() 解析本地文件 html_tree = etree.parse(‘XX.html’) 4.etree.HTML() 服务器响应文件 html_tree = etree.HTML(response.read().decode(‘utf‐8’) 4.html_tree.xpath(xpath路径)
xpath基本语法: 1.路径查询 //:查找所有子孙节点,不考虑层级关系 / :找直接子节点 2.谓词查询 //div[@id] //div[@id=“maincontent”] 3.属性查询 //@class 4.模糊查询 //div[contains(@id, “he”)] //div[starts‐with(@id, “he”)] 5.内容查询 //div/h1/text() 6.逻辑运算 //div[@id=“head” and @class=“s_down”] //title | //price
应用案例: 1.站长素材图片抓取并且下载(http://sc.chinaz.com/tupian/shuaigetupian.html)–》懒加载
例: xpath的基本使用
from lxml import etree
tree = etree.parse('070_爬虫_urllib_xpath的基本使用.html')
'''
// 和/ 的区别
//:查找所有子孙节点,不考虑层级关系
/: 找直接子节点
text(): 获取标签中的内容
@: 定位标签的属性如@id @class
contains(@id,"l"): 检索模糊检索
starts-with(@id,"l"): 以什么字符开头的
and: 和
|: 或,注意不能这样写 //ul/li[@id='l1' | @id = 'l1']/text()
只能这样写 //ul/li[@id='l1']/text() | //ul/li[@id='l2']/text()
'''
li_list = tree.xpath('//body//ul//li')
print(li_list)
li_list = tree.xpath('//ul//li[@id]')
print(li_list)
li_list = tree.xpath('//ul//li[@id]/text()')
print(li_list)
li_list = tree.xpath('//ul//li[@id]/text()')
li_list = tree.xpath('//ul//li[@id="l2"]')
print(li_list)
li = tree.xpath("//ul//li[@id='l1']/@class")
print(li)
li_list = tree.xpath('//ul/li[contains(@id,"l")]')
li_list = tree.xpath('//ul//li[starts-with(@id,"l")]')
li_list = tree.xpath("//ul/li[@id='l1' and @class = 'c1']/text()")
print(li_list)
li_list = tree.xpath(" //ul/li[@id='l1']/text() | //ul/li[@id='l2']/text()")
print(li_list)
案例: xpath 获取百度网站的百度一下
import urllib.request
url="http://www.baidu.com"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
request = urllib.request.Request(url=url,headers= headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
from lxml import etree
tree = etree.HTML(content)
result = tree.xpath('//input[@id="su"]/@value')
print(result)
xpath应用案例: 下载站长素材前十页的图片
import urllib.request
from lxml import etree
def create_request(page):
if(page == 1):
url = 'https://sc.chinaz.com/tupian/dadanrenti.html'
else:
url = 'https://sc.chinaz.com/tupian/dadanrenti_'+str(page)+'.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
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 dowload(content):
tree = etree.HTML(content)
name_list = tree.xpath('//div[@id="container"]//a/img/@alt')
src_list = tree.xpath('//div[@id="container"]//a/img/@src2')
for i in range(len(name_list)):
print(name_list[i],src_list[i])
url = 'https:' + src_list[i]
print(url)
urllib.request.urlretrieve(url=url,filename='./dowload/img/'+name_list[i] + '.jpg')
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)
dowload(content)
三. JsonPath
jsonpath的安装及使用方式:
pip安装:
pip install jsonpath
jsonpath的使用:
obj = json.load(open('json文件', 'r', encoding='utf‐8'))
ret = jsonpath.jsonpath(obj, 'jsonpath语法')
教程连接(http://blog.csdn.net/luxideyao/article/details/77802389) jsonPath的基本使用
{
"store": {
"book": [
{
"category": "修真",
"author": "南派三叔",
"title": "星辰變",
"isbn": "0-395-19395-8",
"price": 22.99
},
{
"category": "修真",
"author": "唐家三少",
"title": "鬥羅大陸",
"isbn": "0-395-19395-8",
"price": 8.99
},
{
"category": "都市",
"author": "天蚕土豆",
"title": "天蚕土豆",
"price": 18.99
}
],
"bicycle": {
"author": "老马",
"color": "黑色",
"price": 19.9
}
}
}
利用JSONpath解析上面的JSON数据
import json
import jsonpath
obj = json.load(open('073_爬虫_urllib_解析_jsonpath.json','r',encoding= 'utf-8'))
author_list = jsonpath.jsonpath(obj,'$.store.book[*].author')
print(author_list)
author_list = jsonpath.jsonpath(obj,'$.store.book[1].author')
print(author_list)
author_list = jsonpath.jsonpath(obj,'$..author')
print(author_list)
author_list = jsonpath.jsonpath(obj,"$.store.*")
print(author_list)
price_list = jsonpath.jsonpath(obj,"$.store..price")
print(price_list)
price_list = jsonpath.jsonpath(obj,"$..book[2]")
print(price_list)
price_list = jsonpath.jsonpath(obj,"$..book[(@.length-1)]")
print(price_list)
price_list = jsonpath.jsonpath(obj,"$..book[0,1]")
print(price_list)
price_list = jsonpath.jsonpath(obj,"$..book[:2]")
print(price_list)
price_list = jsonpath.jsonpath(obj,"$..book[?(@.isbn)]")
print(price_list)
book_list = jsonpath.jsonpath(obj, "$..book[?(@.price > 10)]")
print(book_list)
案例: jsonPath 解析淘票票
import urllib.request
import jsonpath
import json
url = 'https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1649219126937_97&jsoncallback=jsonp98&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
headers = {
'accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 'td_cookie=1358920425; t=7dbc3166374399f2591f65978bc1442e; cookie2=184a378260be631b57c2e87e585d34e6; v=0; _tb_token_=e3374b17369e8; cna=SNYXGm5rLwACAW/E96LhJaH3; xlly_s=1; tfstk=c4iNB3wb_hKZvMZXylZ21e6V4eVOZUHinMy7SVKzHVcXNbzGiNfYdxALL-O1pPf..; l=eBEEU2bmLRJj_gaFBO5Churza779fIRf1lVzaNbMiInca6Q5TFaSSNC3ORbM7dtjgtfndety4GCN_RE6WGUdbgiMW_N-1NKDmxJM-; isg=BKqqAnp4vChGOTBEcvgERLRI-xBMGy51u9HLcDRjsv2IZ0khHKnohb7Z95P7rKYN',
'referer': 'https://dianying.taobao.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
'x-requested-with': 'XMLHttpRequest',
}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
content = content.split('(')[1].split(");")[0]
obj = json.loads(content)
regionNames = jsonpath.jsonpath(obj,'$.returnValue..regionName')
print(regionNames)
四. BeautifulSoup
1.基本简介
1.BeautifulSoup简称:
bs4
2.什么是BeatifulSoup?
BeautifulSoup,和lxml一样,是一个html的解析器,主要功能也是解析和提取数据
3.优缺点?
缺点:效率没有lxml的效率高
优点:接口设计人性化,使用方便
2.安装以及创建
1.安装
pip install bs4
2.导入
from bs4 import BeautifulSoup
3.创建对象
服务器响应的文件生成对象
soup = BeautifulSoup(response.read().decode(), 'lxml')
本地文件生成对象
soup = BeautifulSoup(open('1.html'), 'lxml')
注意:默认打开文件的编码格式gbk所以需要指定打开编码格式
3.节点定位
1.根据标签名查找节点
soup.a 【注】只能找到第一个a
soup.a.name
soup.a.attrs
2.函数
(1).find(返回一个对象)
find('a'):只找到第一个a标签
4.节点信息
应用实例: 1.股票信息提取(http://quote.stockstar.com/)
2.中华英才网-旧版
3 .腾讯公司招聘需求抓取(https://hr.tencent.com/index.php)
find('a', title='名字')
find('a', class_='名字')
(2).find_all(返回一个列表)
find_all('a') 查找到所有的a
find_all(['a', 'span']) 返回所有的a和span
find_all('a', limit=2) 只找前两个a
(3).select(根据选择器得到节点对象)【推荐】
1.element
eg:p
2..class
eg:.firstname
3.#id
eg:#firstname
4.属性选择器
[attribute]
eg:li = soup.select('li[class]')
[attribute=value]
eg:li = soup.select('li[class="hengheng1"]')
5.层级选择器
element element
div p
element>element
div>p
element,element
div,p
eg:soup = soup.select('a,span')
4.节点信息
(1).获取节点内容:适用于标签中嵌套标签的结构
obj.string
obj.get_text()【推荐】
(2).节点的属性
tag.name 获取标签名
eg:tag = find('li)
print(tag.name)
tag.attrs将属性值作为一个字典返回
(3).获取节点属性
obj.attrs.get('title')【常用】
obj.get('title')
obj['title']
应用实例: 1.股票信息提取(http://quote.stockstar.com/) 2.中华英才网-旧版 3 .腾讯公司招聘需求抓取(https://hr.tencent.com/index.php)
bs4的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<ul>
<li id="l1">张三</li>
<li id="l2">李四</li>
<li>王五</li>
<a href="" id="sgg">尚硅谷</a>
<a href="" class="a1">尚硅谷1</a>
<span>span</span>
</ul>
</div>
<a href="" title="啊">百度</a>
<div id="div2">
<span>
hahaha
</span>
</div>
<p id="p1" class="p1"></p>
</body>
</html>
利用bs4 解析上面的html
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('075_爬虫_urllib_bs4的基本使用.html',encoding='utf-8'),'lxml')
print(soup.a)
print(soup.a.attrs)
print(soup.find('a'))
print(soup.find('a',title="啊"))
print(soup.find('a',class_="a1"))
print(soup.findAll('a'))
print(soup.find_all(['a','span']))
print(soup.find_all('li',limit=2))
print(soup.select('a'))
print(soup.select('.a1'))
print(soup.select("#sgg"))
print(soup.select('li[id]'))
print(soup.select('li[id="l2"]'))
print(soup.select('div li'))
print(soup.select('div > ul > li'))
print(soup.select('div>ul>li'))
print(soup.select('a,li'))
obj = soup.select('#div2')[0]
print(obj.get_text())
print(obj.string)
obj = soup.select("#p1")[0]
print(obj.name)
print(obj.attrs)
obj = soup.select('#p1')[0]
print(obj.attrs.get('class'))
print(obj.get("class"))
print(obj['class'])
案例: BS4 爬取星巴克菜单内的图片
import urllib.request
import img as img
from bs4 import BeautifulSoup
url = 'https://www.starbucks.com.cn/menu/'
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
soup = BeautifulSoup(content,'lxml')
name = soup.select("ul[class='grid padded-3 product'] strong")
div = soup.select("ul[class='grid padded-3 product'] div[class='preview circle']")
imgUrl = "https://www.starbucks.com.cn"
def download(name,img):
print('正在下载-->' + name)
try:
urllib.request.urlretrieve(url=imgUrl+img, filename='./dowload/星巴克/' + name + '.jpg')
except Exception:
print("下载失败-->" + name)
for index,item in enumerate(div):
style = item.get('style')
img = style.split("(\"")[1].split("\")")[0]
download(name[index].get_text(),img)
|