requests库
requests库也是一个网络请求库, 基于urllib和urllib3封装的便捷使用的网络请求库。
安装环境
pip install requests -i https://mirrors.aliyun.com/pypi/simple
核心的函数
-
requests.request() 所有请求方法的基本方法
以下是request()方法的参数说明
-
method: str 指定请求方法, GET, POST, PUT, DELETE
-
url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
-
params: dict , 用于GET请求的查询参数(Query String params);
-
data: dict , 用于POST/PUT/DELETE 请求的表单参数(Form Data)
-
json: dict 用于上传json数据的参数, 封装到body(请求体)中。请求头的Content-Type默认设置为
application/json
-
files: dict, 结构 {‘name’: file-like-object | tuple}, 如果是tuple, 则有三种情况:
- (‘filename’, file-like-object)
- (‘filename’, file-like-object, content_type)
- (‘filename’, file-like-object, content_type, custom-headers)
指定files用于上传文件, 一般使用post请求,默认请求头的
Content-Type
为multipart/form-data
类型。 -
headers/cookies : dict
-
proxies: dict , 设置代理
-
auth: tuple , 用于授权的用户名和口令, 形式(‘username’, ‘pwd’)
-
-
requests.get() 发起GET请求, 查询数据
可用参数:
- url
- params
- json
- headers/cookies/auth
-
requests.post() 发起POST请求, 上传/添加数据
可用参数:
- url
- data/files
- json
- headers/cookies/auth
-
requests.put() 发起PUT请求, 修改或更新数据
-
requests.patch() HTTP幂等性的问题,可能会出现重复处理, 不建议使用。用于更新数据
-
requests.delete() 发起DELETE请求,删除数据
requests.Respose
以上的请求方法返回的对象类型是Response, 对象常用的属性如下:
-
status_code 响应状态码
-
url 请求的url
-
headers : dict 响应的头, 相对于urllib的响应对象的getheaders(),但不包含cookie。
-
cookies: 可迭代的对象,元素是Cookie类对象(name, value, path)
-
text : 响应的文本信息
-
content: 响应的字节数据
-
encoding: 响应数据的编码字符集, 如utf-8, gbk, gb2312
-
json(): 如果响应数据类型为
application/json
,则将响应的数据进行反序化成python的list或dict对象。- 扩展-javascript的序列化和反序列化
- JSON.stringify(obj) 序列化
- JSON.parse(text) 反序列化
- 扩展-javascript的序列化和反序列化
requests库小练习
"""
spider_02_requests_request.py
"""
import requests
from requests import Response
def get_douban_movie():
base_url='https://movie.douban.com/j/chart/top_list'
params={
'type' : 5 ,
'interval_id': '100:90' ,
'action' : ''
}
data = {
'start' : 0,
'limit' : 20
}
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
}
resp=requests.post(url=base_url,params=params,data=data,headers=headers)
assert resp.status_code==200
print(resp.url)
if 'application/json' in resp.headers['Content-Type']:
return resp.json()
else:
return resp.text
def get_anjuke():
"""
有反爬虫
"""
url='https://nc.anjuke.com/community/'
params={
'from':'navigation'
}
resp=requests.get(url=url,params=params)
assert resp.status_code==200
print(resp.content.decode('utf-8'))
if __name__ == '__main__':
resp=get_douban_movie()
print(resp)
# get_anjuke() //有反爬虫
数据解析方式之xpath
xpath属于xml/html解析数据的一种方式, 基于元素(Element)的树形结构(Node > Element)。选择某一元素时,根据元素的路径选择,如
/html/head/title
获取<title>
标签。
安装xpath库
安装包 pip install lxml
引用 form lxml import etree
root=etree.HTML(html)
divs =root.xpath()
绝对路径
从根标签开始,按tree结构依次向下查询。
如 /html/body/table/tbody/tr。
相对路径
相对路径可以有以下写法
-
相对于整个文档
//img
查找出文档中所有的
<img>
标签元素 -
相对于当前节点
//table
假如当前节点是
<table>
, 查找它的<img>
的路径的写法.//img
数据提取
-
提取文本
//title/text()
-
提取属性
//img/@href
位置条件
获取网页中的数据类型与字符集, 获取第一个<meta>
标签
//meta[1]//@content
获取最后一个<meta>
标签
//meta[last()]//@content
获取倒数第二个<meta>
标签
//meta[position()-2]//@content
获取前三个<meta>
标签
//meta[position()<3]//@content
属性条件
查找 class为circle-img
的<img>
标签
//img[@class="circle-img"]
同时提取两个元素
//title/text() | //img/@src
模糊条件
//div[contains(@class, "page")]
查找class属性包含page的所有div标签//div[starts-with(@class, "box")]
第一个class的属性值为box的div标签//div[ends-with(@class, "clearfix")]
最一个class的属性值为clearfix的div标签
xpath小练习
# spider_02_requests_xpath.py
"""
request发起网络请求
xpath进行数据解析
"""
import requests
from lxml import etree
header={
'User-Agent' :'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
}
# proxy={
# 'http':'http://120.220.220.95:8085'
# }
def get_request(url):
resp=requests.get(url,headers=header)
if resp.status_code==200:
parse_html(resp.text)
else:
print("请求失败!")
def parse_html(html):
root=etree.HTML(html)
divs= root.xpath('//div[@class="left"]/div[@class="sons"]') # list[<Element>, ..]
print(divs)
for div in divs:
title=div.xpath('.//div[@class="cont"]/p[1]/a/b/text()')
author=div.xpath('.//div[@class="cont"]/p[2]/a/text()')
content=div.xpath('.//div[@class="cont"]/div[@class="contson"]/text()')
print(title,author,content)
if __name__ == '__main__':
get_request('https://www.gushiwen.cn/')
xpath编写小妙招
有的时候自己审查,编写表达式,有一点点的小麻烦,比较快速的方法,就是直接选中目标元素,右键选择Copy,找到Copy Xpath/Copy full Xpath,作为参考,就能很快写出符合自身的表达式。
Copy Xpath
//*[@id="leftZhankai"]/div[2]/div[1]/p[1]/a/b
Copy full Xpath
/html/body/div[2]/div[1]/div[2]/div[2]/div[1]/p[1]/a/b
导出csv文件小练习
"""
抓取信息导出CSV文件
"""
import requests
import uuid
import os
from lxml import etree
from csv import DictWriter
header={
'User-Agent' :'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
}
params={
'page':''
}
def get_request(pages):
url='https://so.gushiwen.cn/shiwens/default.aspx?'
for page in range(1,pages+1):
params['page']=page
resp = requests.get(url, headers=header,params=params)
print('正在获取第 %s 页诗词!' %page)
if resp.status_code == 200:
parse_html(resp.text)
else:
print("请求失败!")
def parse_html(html):
root = etree.HTML(html)
# pages=root.xpath('/html/body/div[2]/div[1]/div[2]/form/div/label[2]/text()')
# pages=int(pages[0])
# print(pages)
divs = root.xpath('//div[@class="left"]/div[@id="leftZhankai"]/div[@class="sons"]') # list[<Element>, ..]
print(divs)
item={}
for div in divs:
item['id'] = uuid.uuid4().hex
item['title'] =div.xpath('.//div[@class="cont"]/p[1]/a/b/text()')[0]
item['author']= ''.join(div.xpath('.//div[@class="cont"]/p[2]/a/text()'))
item['content'] = ''.join(div.xpath('.//div[@class="cont"]/div[@class="contson"]/text()'))
itempipe4csv(item)
has_header = os.path.exists('dushuwang.csv') # 是否第一次写入csv的头
header_fields = ('id', 'title', 'author', 'content')
def itempipe4csv(item):
print(item)
global has_header
with open('dushuwang.csv', 'a', encoding='utf-8',newline='') as f:
#newline='' 解决CSV换行问题
writer = DictWriter(f, fieldnames=header_fields)
if not has_header:
writer.writeheader() # 写入第一行的标题
has_header = True
writer.writerow(item) # 写入数据
if __name__ == '__main__':
get_request(5)