Python爬虫_03_urllib_xpath_JsonPath_BeautifulSoup应用及案例

一.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的基本使用

# 使用urllib 来获取百度首页的源码
import urllib.request
# 1. 定义一个url,就是要访问的地址
url = 'http://www.baidu.com'
# 2. 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)
# 3. 获取响应中的页面的源码
# read 方法,返回的是字节形式的二进制数据
# 我们要讲二进制的数据转换为字符串
# 二进制 --> 字符串 解码 decode('编码格式')
content = response.read().decode('utf-8')
# 4. 打印数据
print(content)

例: urllib 一个类型和6个方法

# _*_ coding: utf-8 _*_
# @Time  17:06
# @Author: He
# @File 054_爬虫_urllib_1个类型6个方法.py
# @Project python基础
import urllib.request
url = 'http://wwww.baidu.com'
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)

# 一个类型和六个方法
# response 是httpResponse 类型
# print(type(response)) #<class 'http.client.HTTPResponse'>

# 按照一个字节一个字节读取
# content = response.read()
# print(content)

# 返回多少个字节
# content = response.read(5)

# 读取一行
# content = response.readline()

# 一行一行读.直至读完
# content = response.readlines()
# print(content)

#  返回状态吗,如果是200,那么就证明我们的逻辑没有错
print(response.getcode())

#  返回url地址
print(response.geturl())

# 获取的是状态信息
print(response.getheaders())

# 一个类型 HTTPResponse
# 六个方法: read readline readlines getcode geturl getheaders

例: urllib 下载视频图片音乐

import urllib.request

# 下载网页
# url_page = 'http://www.baidu.com'
# url 代表的是下载的路径,filename 文件的名字
# 在python中 可以变量的名字,也可以直接写值
# urllib.request.urlretrieve(url_page,'baidu.html')
# 下载图片
# url_img = 'https://img0.baidu.com/it/u=1532195562,2972426089&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=647'
# urllib.request.urlretrieve(url_img,'img.jpg')

# 下载视频
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 '

# url的组成
# http/https www.baidu.com      80/443       s    wd=周杰伦     #
# 协议            主机             端口号      路径    参数      锚点
# http 80
# https 443
# mysql 3306
# oracel 1521
# redis 6379
# mongodb 2701
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'
}
# 因为urlopen 方法中不能存储字典,所以headers不能传递进去
# 请求对象的定制
# 注意 因为参数顺序的问题,不能直接写url和 headers 中间还有data,所以我们需要关键字传参
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()

# 需求https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=周杰伦网页源码


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'

}

# 将周杰伦三个字变成unicode编码的格式
# 我们需要依赖于urllib.parse
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()

#  urlencode应用场景:多个参数的时候
# import urllib.parse
# data :{
#     'wd': '周杰伦',
#     'sex': '男'
# }
# urllib.parse.urlencode(data)

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请求方式

# eg:百度翻译
# 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': '美女',
}

# post 请求的参数,必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
# post 请求的参数是不会拼接在url的后面的,而是需要放在请求对象定制的参数中

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)) #{'errno': 0, 'data': [{'k': '美女', 'v': 'beauty; belle; beautiful woman; femme fatale; peri'}, {'k': '美女蛇', 'v': 'merino'}, {'k': '美女与野兽', 'v': '名. Beauty and the Beast'}]}


'''
总结:
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这个属性必须注释掉'Accept-Encoding': 'gzip, deflate, br',
# 百度翻译的反扒手段只需要一个Cookie
headers = {
    # 'Accept': '*/*',
    # # 'Accept-Encoding': 'gzip, deflate, br',
    # 'Accept-Language': 'zh-CN,zh;q=0.9',
    # 'Connection': 'keep-alive',
    # 'Content-Length': 150,
    # 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    '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==',
    # 'Host': 'fanyi.baidu.com',
    # 'Origin': 'https://fanyi.baidu.com',
    # 'Referer': 'https://fanyi.baidu.com/?aldtype=16047',
    # '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'
}
data = {
    'from': 'zh',
    'to': 'en',
    'query': '美女',
    'transtype': 'translang',
    'simple_means_flag': 3,
    'sign': 551517.821612,
    'token': 'fcb141eb5cc8b83af203e132e27bcb76',
    'domain': 'common',
}
#  post 请求的参数必须进行编码并且调用encode
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"
# 1. 请求对象的定制
request = urllib.request.Request(url = url,headers= headers)
# 2. 获取响应的数据
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')

#3.数据下载到本地
# open 方法默认情况下使用的是gbk的编码,如果我们要想保存汉子,那么需要在open方法中指定编码格式为utf-8
# encoding='utf-8'
# fd = open("dowload/douban.json",'w',encoding='utf-8')
# fd.write(content)
# fd.close()

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
# 下载豆瓣电影前10页的数据
#  1.请求对象的定制
# 2. 获取响应的数据
#  3. 下载数据
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登陆

# 适用的场景:数据采集的时候 需要绕过登录 然后进入到某个页面
# 个人信息页面是utf-8 但是还报错了编码错误 因为并没有进入到个人信息页面 而是跳到了登录页面
# 那么登录页面不是utf-8 所以报错

# 什么情况下访问不成功?
# 因为请求头的信息不够,所有访问不成功
import urllib.request

url = 'https://weibo.com/u/7751984183/home'
headers = {
    # ':authority': 'weibo.com',
    # ':method': 'GET',
    # ':path': '/ajax/log/action?type=pic&uicode=20000390&fid=232150&act_code=4288&ext=module%3A01&luicode=&t=1649144295190',
    # ':scheme': 'https',
    'accept': 'application/json, text/plain, */*',
    # 'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9',
    # cookie 中携带者你的登录信息,如果有登录之后的cookie 那么我们就可以携带者cookie进入到任何页面
    '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判断当前路径是不是由上一个路径进来的,一般情况下是做图片防盗链
    '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和代理
不能使用请求对象的定制)
#  需求: 使用handler 来访问百度获取源码
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 bulid_opener open

# 1 获取handler对象
handler = urllib.request.HTTPHandler

# 2 获取opener对象
opener = urllib.request.build_opener(handler)

# 3 調用open方法
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函数发送请求
#  需求: 使用handler 来访问百度获取源码
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)

# handler bulid_opener open
proxies = {
    # ip可百度快代理,有免費的IP可用
    'http': '47.113.90.161:83',
}
# 1 获取handler对象
handler = urllib.request.ProxyHandler(proxies=proxies)

# 2 获取opener对象
opener = urllib.request.build_opener(handler)

# 3 調用open方法
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) # 随机从代理池中获取ip
	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

# xpath 解析
# 1 本地文件 etree.parse
# xpath 解析本地文件
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()
'''
# 查找ul 下面的li
li_list = tree.xpath('//body//ul//li') # 路径查询
print(li_list)

# 查找所有有ID的属性的li标签
li_list = tree.xpath('//ul//li[@id]')
print(li_list)

# 查找所有有ID的属性的li标签的内容
li_list = tree.xpath('//ul//li[@id]/text()')
print(li_list)
li_list = tree.xpath('//ul//li[@id]/text()')

# 查找id为li的l2标签
li_list = tree.xpath('//ul//li[@id="l2"]')
print(li_list)

# 查找id 为l1的li标签的class的 属性值
li = tree.xpath("//ul//li[@id='l1']/@class")
print(li)

# 模糊查询
# 查找id中包含l的li标签
li_list = tree.xpath('//ul/li[contains(@id,"l")]')

# 查询id的值以l开头的li标签
li_list = tree.xpath('//ul//li[starts-with(@id,"l")]')

# 查询id 为li 和class 为c1的
li_list = tree.xpath("//ul/li[@id='l1' and @class = 'c1']/text()")
print(li_list)

# 查询id 为li 和class 为c1的
li_list = tree.xpath(" //ul/li[@id='l1']/text() | //ul/li[@id='l2']/text()")
print(li_list)

# 2 服务器响应的数据 response.read().decode('utf-8')   etree.HTML()

案例: xpath 获取百度网站的百度一下

# 1 获取网页的源码
# 2 解析 解析的服务响应的文件 etree.HTML
# 3 打印

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)

#  获取想要的数据,xpath 返回值是一个列表的数据
result = tree.xpath('//input[@id="su"]/@value')
print(result)

xpath应用案例: 下载站长素材前十页的图片


# 1 请求对象的定制
# 2 获取网页的源码
# 3 下载

# 需求 下载前10页的图片
# https://sc.chinaz.com/tupian/dadanrenti.html
# https://sc.chinaz.com/tupian/dadanrenti_2.html
# 分析路径_2为page页码

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):
    #     下载图片
    # urllib.request.urlretrieve("图片地址","文件名字")
    # 数据清洗
    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]) #优优人体大胆艺术写真图片 //scpic3.chinaz.net/Files/pic/pic9/202010/apic28507_s.jpg
        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)

# store 下面所有的元素
author_list = jsonpath.jsonpath(obj,"$.store.*")
print(author_list)

# store 里面的所有东西的price
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)

# 条件过滤需要在圆括号前加一个?号
# 过滤除所有 的包含ison的书
price_list = jsonpath.jsonpath(obj,"$..book[?(@.isbn)]")
print(price_list)

# 哪本书超过了10元
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-encoding': 'gzip, deflate, br',
    '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')
# split切割
content = content.split('(')[1].split(");")[0]

# 将json字符串直接转换json对象,不用存到本地再读出来那么麻烦
# with open('074_爬虫_urllib_jsonpath解析淘票票.json','w',encoding='utf-8') as fp:
#     fp.write(content)
# obj = json.load(open('074_爬虫_urllib_jsonpath解析淘票票.json','r',encoding='utf-8'))

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

# 通过解析本地文件来将bs4的基本语法进行讲解
# 默认打开文件的编码格式是gbk,所以在打开文件的时候需要指定编码
soup = BeautifulSoup(open('075_爬虫_urllib_bs4的基本使用.html',encoding='utf-8'),'lxml')

#  根据标签名查找节点
# 找到的是第一个符合条件的数据
print(soup.a) # <a href="">尚硅谷</a>

# 获取标签的属性和属性值
print(soup.a.attrs) #{'href': '', 'id': ''}

# bs4 的一些函数
# 1. find
# 返回的是第一个符合条件的数据
print(soup.find('a')) # <a href="" id="">尚硅谷</a>
# 根据title的值找到对应的对象
print(soup.find('a',title="啊")) #<a href="" title="啊">百度</a>
# 根据class的值来找到对象的标签对象,注意的是class需要添加下划线
print(soup.find('a',class_="a1")) #<a class="a1" href="">尚硅谷1</a>

# 2. findAll
# 返回的是一个列表,并且返回了所有的a标签
print(soup.findAll('a')) #[<a href="" id="">尚硅谷</a>, <a class="a1" href="">尚硅谷1</a>, <a href="" title="啊">百度</a>]

# 如果想获取的是多个标签的数据,那么需要在find_all的参数中添加的是列表的数据
print(soup.find_all(['a','span'])) #[<a href="" id="">尚硅谷</a>, <a class="a1" href="">尚硅谷1</a>, <span>span</span>, <a href="" title="啊">百度</a>]

# limit的作用是查找前几个数据
print(soup.find_all('li',limit=2)) #[<a href="" id="">尚硅谷</a>, <a class="a1" href="">尚硅谷1</a>, <span>span</span>, <a href="" title="啊">百度</a>]


# 3. select
# select 方法的返回是一个列表 并且会返回多个数据
print(soup.select('a')) #[<a href="" id="">尚硅谷</a>, <a class="a1" href="">尚硅谷1</a>, <a href="" title="啊">百度</a>]

# 可以通过.代表class ,我们吧这种操作叫做类选择器
print(soup.select('.a1')) #[<a class="a1" href="">尚硅谷1</a>]

# id选择器
print(soup.select("#sgg")) #[<a href="" id="sgg">尚硅谷</a>]

# 属性选择器--通过属性来寻找对应的标签
# 查找到li标签中在id的标签
print(soup.select('li[id]')) #[<li id="l1">张三</li>, <li id="l2">李四</li>]

# 查找到li 标签中id为l2的标签
print(soup.select('li[id="l2"]')) #[<li id="l2">李四</li>]

# 层级选择器
# 后代选择器
# 找到div下面的li
print(soup.select('div li')) #[<li id="l1">张三</li>, <li id="l2">李四</li>, <li>王五</li>]

# 子代选择器
# 某标签的第一集子标签
# 注意:很多的计算机编程语言中,如果不加空格不会输出内容,但是在bs4中,不会报错,会显示内容
print(soup.select('div > ul > li')) #[<li id="l1">张三</li>, <li id="l2">李四</li>, <li>王五</li>]
print(soup.select('div>ul>li')) #[<li id="l1">张三</li>, <li id="l2">李四</li>, <li>王五</li>]

# 找到a标签 和li 标签所有的对象
print(soup.select('a,li'))

# 节点信息
# 回去节点内容
obj = soup.select('#div2')[0]
# 如果标签对象中只有内容,那么String和get_text()都可以使用
# 如果标签对象中,除了内容还有标签,那么string就获取不到数据,而get_text()是可以获取数据
# 我们一般情况下推荐使用get_text()
print(obj.get_text())
print(obj.string)

# 节点属性
obj = soup.select("#p1")[0]
# name 是标签的名字
print(obj.name) # p

# 将属性值作为一个字典返回
print(obj.attrs) #{'id': 'p1', 'class': ['p1']}

# 获取节点属性
obj = soup.select('#p1')[0]
print(obj.attrs.get('class')) #['p1']
print(obj.get("class")) #['p1']
print(obj['class'])#['p1']

案例: 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')
# //ul[@class='grid padded-3 product']//strong
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" # img的图片路径不完整,我们需要在图片的路径上加上它的域名
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] #/images/products/9oz-reserve-glass-cup.jpg
    download(name[index].get_text(),img)
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值