东营网站建设哪家好,深圳市网页制作,衡东网站制作,展览设计网站推荐文章目录 一、urllib1. urlparse 实现 URL 的识别和分段2. urlunparse 用于构造 URL3. urljoin 用于两个链接的拼接4. urlencode 将 params 字典序列化为 params 字符串5. parse_qs 和 parse_qsl 用于将 params 字符串反序列化为 params 字典或列表6. quote 和 unquote 对 URL的… 文章目录 一、urllib1. urlparse 实现 URL 的识别和分段2. urlunparse 用于构造 URL3. urljoin 用于两个链接的拼接4. urlencode 将 params 字典序列化为 params 字符串5. parse_qs 和 parse_qsl 用于将 params 字符串反序列化为 params 字典或列表6. quote 和 unquote 对 URL的中文字符进行编码和解码 二、requests1. GET 请求2. POST 请求3. Session 维持4. 响应5. 身份认证6. 设置代理7. Prepared Request 三、httpx1. Requests Compatibility2. 异步 四、基础爬虫实战 一、urllib
urllib 类似于 python 底层构建请求构建相对于其他的库来说较为复杂不过 urllib 解析链接非常好用
1. urlparse 实现 URL 的识别和分段
如果需要合并 params 和 query 可以使用 urlsplit
from urllib.parse import urlparseurlparse(https://www.baidu.com/)# ParseResult(schemehttps, netloc[www.baidu.com](https://www.baidu.com/), path/, params, query, fragment)2. urlunparse 用于构造 URL
urlunparse 这个方法接收的参数是一个可迭代对象且其长度必须为 6同样的如果需要合并 params 和 query 可以使用 urlunsplit
from urllib.parse import urlunparsedata [https,www.baidu.com,index.html,user,a6,comment]urlunparse(data)
# https://www.baidu.com/index.html;user?a6#comment3. urljoin 用于两个链接的拼接
urljoin 首先会解析 new_url判断其 schemenetlocpath 是否出现了缺失如果确实使用 base_url 中的 schemenetlocpath 对应缺失部分代替
from urllib.parse import urljoinbase_url https://www.baidu.com
new_url FAQ.htmlurljoin(base_url, new_url)
# https://www.baidu.com/FAQ.html4. urlencode 将 params 字典序列化为 params 字符串
from urllib.parse import urlencodeparams {name: germey,age: 2,
}base_url https://www.baidu.com?
base_url urlencode(params)
# https://www.baidu.com?namegermeyage25. parse_qs 和 parse_qsl 用于将 params 字符串反序列化为 params 字典或列表
from urllib.parse import parse_qs, parse_qslparams namegermeyage25parse_qs(params, separator)
# {name: [germey], age: [25]}parse_qsl(params, separator)
[(name, germey), (age, 25)]6. quote 和 unquote 对 URL的中文字符进行编码和解码
from urllib.parse import quote, unquoteurl https://www.baidu.com/s?wd爬虫# utf8编码指定安全字符
quote(url, safe;/?:$,, encodingutf-8)
# https://www.baidu.com/s?wd%E7%88%AC%E8%99%AB# gbk编码指定安全字符
quote(url, safe;/?:$,, encodinggbk)
# https://www.baidu.com/s?wd%C5%C0%B3%E6# utf8解码
unquote(https://www.baidu.com/s?wd%E7%88%AC%E8%99%AB, encodingutf-8)
# https://www.baidu.com/s?wd爬虫# gbk解码
unquote(https://www.baidu.com/s?wd%C5%C0%B3%E6, encodinggbk)
# https://www.baidu.com/s?wd爬虫二、requests
1. GET 请求
测试 URL www.httpbin.org/get
cookies 可以单独设置也可以放在 headers 的 cookie 字段下传入请求之中timeout 可以控制超时时间headers 是请求头params 是参数构建完整的 url
import requestsparams {}
headers {}
cookies {}# vertify 设置为 False 可以避免 ssl 认证
requests.get(urlurl, paramsparams, headersheaders, cookiescookies, vertifyFalse, timeoutNone)
2. POST 请求
测试 URL www.httpbin.org/post
POST 是上传东西的常用请求POST 请求中除了 GET 请求中的那些参数还有一些参数可以使用如 data 和 file其中 data 主要用来传表单而 file 主要用来传文件
import requestsparams {}
headers {}
cookies {}data {}
file {}# vertify 设置为 False 可以避免 ssl 认证
requests.post(urlurl, paramsparams, headersheaders, cookiescookies, vertifyFalse, timeoutNone, datadata, filefile)3. Session 维持
多次直接利用 requests 库中的 get 或 post 方法模拟网络请求相当于打开了多个不同的浏览器而使用 Session 维持 搭配 get 和 post 方法去模拟网络请求相当于打开了一个浏览器中的多个页面
import requestss requests.Session(headersheaders)
s.get(url_1)
s.get(url_2)# 这里在第一次 get 请求中获得到的 cookie 就会保持进而在第二次 get 请求中得到4. 响应
import requestsresp requests.get()# 状态码
resp.status_code# 响应头
resp.headers# cookies
resp.cookies# 最终 url 搭配重定向使用 requests.get(url, allow_redirectsFalse)
resp.url# 请求历史
resp.history# 在获取 resp.text 先配置 encoding
resp.encoding# 响应结果字符串形式需要搭配 resp.encoding utf-8 or gbk 使用
resp.text# 二进制相应结果通常对应于文件
resp.content# resp.text 转化为 json 数据如果不是json 数据格式则会出现解析错误抛出 json.decoder.JSONDecodeError 异常
resp.json5. 身份认证
在访问启用了基本身份认证的网站时首先会弹出一个认证窗口认证正确会弹出 200状态码如果认证错误或者不进行认证会弹出 401 错误
import requests
from requests.auth import HTTPBasicAuth# 第一行是第二行的简写
r requests.get(https://ssr3.scrape.center/,auth(admin,admin))
r requests.get(https://ssr3.scrape.center/,authHTTPBasicAuth(admin,admin))r.status_code
# 200requests 库还提供了其他的认证方式如 OAuth 认证需要安装 oauth 包
6. 设置代理
首先是基本的 HTTP 代理
import requestsproxies {http:http://10.10.10,10:1080,https:https://10.10.10.10:1080,
}requests.get(https://www.httpbin.org/get, proxiesproxies)除了基本的 HTTP 代理外还支持 SOCKS 协议的代理首先需要安装 socks 库 pip install requests[socks]
import requestsproxies {http:socks5://10.10.10,10:1080,https:socks5://10.10.10.10:1080,
}requests.get(https://www.httpbin.org/get, proxiesproxies)7. Prepared Request
因此多个 get 或者 post 请求相当于多个 Session尽量避免对同一网页使用多个 get 或者 post 请求
from requests import Request,Sessionurl https://www.httpbin.org/post
data {name:germey}
headers {}# 请求的底层
s Session()
req Request(POST, url, datadata, headersheaders)
prepped s.prepare_request(req)
r s.send(prepped)# 等价
r requests.post(url, datadata, headersheaders)三、httpx
HTTPX 建立在 requests 完善的可用性之上支持 HTTP/2 并支持异步HTTPX (python-httpx.org)
可选安装如下
h2 - HTTP/2 支持。 可选带有 httpx[http2] socksio - SOCKS 代理支持。 可选带有 httpx[socks] brotli 或 brotlicffi - 解码“brotli”压缩响应。 可选带有 httpx[brotli]
HTTPX 与 requests 的 API 广泛兼容在少部分地方存在一些设计差异Requests Compatibility - HTTPX (python-httpx.org)
1. Requests Compatibility
重定向与 requests 不同HTTPX 默认情况下是不遵循 重定向 (redirects) 的开启重定向如下所示
client httpx.Client(follow_redirectsTrue)
response client.get(url, follow_redirectsTrue)Client等价于 requests.Session 维持即等价
session requests.Session(**kwargs)
client httpx.Client(**kwargs)URL访问 response.url 将返回 url 实例requests 返回的是字符串
重定向请求requests 库公开了一个属性 response.next 该属性可用于获取下一个重定向请求。在 HTTPX 中此属性被命名为 response.next_request 。
# requests
session requests.Session()
request requests.Request(GET, ...).prepare()
while request is not None:response session.send(request, allow_redirectsFalse)request response.next# httpx
client httpx.Client()
request client.build_request(GET, ...)
while request is not None:response client.send(request)request response.next_request请求内容对于上传原始文本或二进制内容httpx 使用 content 参数以便更好地将这种用法与上传表单数据的情况分开。使用 content... 上传原始内容并使用 data... 发送表单数据
httpx.post(..., contentbHello, world)
httpx.post(..., data{message: Hello, world})上传文件HTTPX 严格强制上传文件必须以二进制模式打开以避免尝试上传以文本模式打开的文件可能导致的字符编码问题。
内容编码HTTPX 使用 utf-8 来编码 str 请求正文。例如当使用 contentstr 时请求正文将在通过线路发送之前编码为 utf-8 。
Cookietrust_env 、 verify 和 cert 参数如果使用客户端实例应始终在客户端实例化时传递而不是传递给请求方法。
2. 异步
requests 是不支持异步的通常我们会使用 aiohttp 来进行异步操作而 httpx 不仅支持同步还支持异步
import asyncio
import httpxasync def main():async with httpx.AsyncClient() as client:response await client.get(https://www.example.com/)print(response)asyncio.run(main())四、基础爬虫实战
任务
使用爬虫基本库爬取 https://ssr1.scrape.center/ 每一页的电影列表顺着列表再爬取每个电影的详细页使用正则表达式提取每部电影的名称封面类别上映时间剧情简介等内容使用多进程实现爬取的加速
流程 代码
import os
import re
import httpx
import json
from multiprocessing import Pool
from urllib.parse import urljoinbase_url https://ssr1.scrape.centerdef scrape_index(page):获得page的urlpage_url f{base_url}/page/{page}return page_urldef scrape_list(html):获得列表的urlurl_list re.findall(ra data.* href(.*) classname, html)url_list [urljoin(base_url, item) for item in url_list]return url_listdef scrape_detail(html):获得详细页信息detail_dic {}detail_dic[名称] (re.search(rh2 data.*? classm-b-sm(.*?)/h2, html, re.S).group(1)if re.search(rh2 data.*? classm-b-sm(.*?)/h2, html, re.S)else None)detail_dic[封面] (re.search(rclassitem.*?img.*?src(.*?).*?classcover, html, re.S).group(1)if re.search(rclassitem.*?img.*?src(.*?).*?classcover, html, re.S)else None)detail_dic[类别] re.findall(rbutton.*?category.*?span(.*?)/span.*?/button, html, re.S)detail_dic[上映时间] (re.search(rspan.*?(\d{4}-\d{2}-\d{2}) 上映, html, re.S).group(1)if re.search(rspan.*?(\d{4}-\d{2}-\d{2}) 上映, html, re.S)else None)detail_dic[剧情简介] (re.search(r剧情简介/h3.*?p.*?(.*?)/p, html, re.S).group(1).strip()if re.search(r剧情简介/h3.*?p.*?(.*?)/p, html, re.S)else None)return detail_dicdef validateTitle(title):命名规范性rstr r[\/\\\:\*\?\\\\|] # / \ : * ? |new_title re.sub(rstr, _, title) # 替换为下划线return new_titledef save_json(detail_dic):保存数据到json文件夹下os.makedirs(./json, exist_okTrue)name detail_dic[名称]data_path f./json/{validateTitle(name)}.jsonjson.dump(detail_dic, open(data_path, w, encodingutf-8), ensure_asciiFalse, indent2)def main(page):client httpx.Client()page_url scrape_index(page)resp_page client.get(page_url).texturl_list scrape_list(resp_page)for detail_url in url_list:resp_detail client.get(detail_url).textdetail_dic scrape_detail(resp_detail)save_json(detail_dic)if __name__ __main__:pool Pool(10)pages range(1, 10 1)pool.map(main, pages)pool.close()pool.join()得到结果如下