python - 在网页抓取脚本上出现 403 错误
问题描述
我有一个最近遇到 403 错误的网页抓取脚本。它只使用基本代码工作了一段时间,但现在遇到了 403 错误。我已经尝试使用用户代理来规避这个问题,它的工作非常短暂,但现在也出现了 403 错误。
有谁知道如何让这个脚本再次运行?
如果有帮助,这里有一些上下文:脚本的目的是找出哪些艺术家在哪些潮汐播放列表上,为了这个问题 - 我只包含了获取网站的代码片段,因为那是发生错误。
提前致谢!
基本代码如下所示:
baseurl = 'https://tidal.com/browse'
for i in platformlist:
url = baseurl+str(i[0])
tidal = requests.get(url)
tidal.raise_for_status()
if tidal.status_code != 200:
print ("Website Error: ", url)
pass
else:
soup = bs4.BeautifulSoup(tidal.text,"lxml")
text = str(soup)
text2 = text.lower()
使用用户代理:
user_agent_list = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
]
url = 'https://tidal.com/playlist/1b418bb8-90a7-4f87-901d-707993838346'
for i in range(1,4):
#Pick a random user agent
user_agent = random.choice(user_agent_list)
#Set the headers
headers = {'User-Agent': user_agent}
#Make the request
tidal = requests.get(url,headers=headers)
print("Request #%d\nUser-Agent Sent:%s\n\nHeaders Received by HTTPBin:"%(i,user_agent))
print(tidal.status_code)
print("-------------------")
#tidal = requests.get(webpage)
tidal.raise_for_status()
print(tidal.status_code)
#make webpage content legible
soup = bs4.BeautifulSoup(tidal.text,"lxml")
print(soup)
#turn bs4 type content into text
text = str(soup)
text2 = text.lower()
解决方案
我想提出一个替代解决方案 - 一个不涉及 BeautifulSoup 的解决方案。
我访问了主页并单击了一个相册,同时记录了我的网络流量。我注意到我的浏览器向 GraphQL API 发出了 HTTP POST 请求,该 API 接受自定义查询字符串作为 POST 有效负载的一部分,该有效负载指示响应数据的格式。响应是 JSON,它包含我们使用原始查询字符串请求的所有信息(在这种情况下,播放列表的每个曲目的所有艺术家)。通常,页面使用此 API 来使用 JavaScript 异步填充自身,这通常是在浏览器中查看页面时发生的情况,就像它本来的样子。由于我们有 API 端点、请求标头和 POST 有效负载,我们可以在 Python 中模仿该请求以获取 JSON 响应:
def main():
import requests
url = "https://tidal.com/browse/api"
headers = {
"accept": "application/json",
"accept-encoding": "gzip, deflate",
"content-type": "application/json",
"user-agent": "Mozilla/5.0"
}
query = """
query ($playlistId: String!) {
playlist(uuid: $playlistId) {
creator {
name
}
title
tracks {
albumID
albumTitle
artists {
id
name
}
id
title
}
}
}
"""
payload = {
"operationName": None,
"query": query,
"variables": {
"playlistId": "1b418bb8-90a7-4f87-901d-707993838346"
}
}
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
playlist = response.json()["data"]["playlist"]
print("Artists in playlist \"{}\":".format(playlist["title"]))
for track_number, track in enumerate(playlist["tracks"], start=1):
artists = ", ".join(artist["name"] for artist in track["artists"])
print("Track #{} [{}]: {}".format(track_number, track["title"], artists))
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
输出:
Artists in playlist "New Arrivals":
Track #1 [Higher Power]: Coldplay
Track #2 [i n t e r l u d e]: J. Cole
Track #3 [Fast (Motion)]: Saweetie
Track #4 [Miss The Rage]: Trippie Redd, Playboi Carti
Track #5 [In My Feelings (feat. Quavo & Young Dolph)]: Tee Grizzley, Quavo, Young Dolph
Track #6 [Thumbin]: Kash Doll
Track #7 [Tiempo]: Ozuna
...
您可以更改字典中的playlistId
键值对payload
以获取任何播放列表的艺术家信息。
看看我发布的另一个答案,我在其中更深入地介绍了如何记录您的网络流量、查找 API 端点和模仿请求。
推荐阅读
- python-3.x - Python 3.x:尝试遍历列表中的每个项目,然后计算项目是否在某些时间间隔内减少或增加
- c - 从C中的文件中读取unicode字符
- multithreading - 多线程:chromedriver 不在第二个窗口中打开 url
- c# - 无法加载文件或程序集 'System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 或其依赖项之一
- javascript - 如何在手风琴中打开下一个标签?
- spring-boot - 让 Jackson 在 Spring Boot 中忽略控制器级别的某些字段
- nginx - 本地主机上的 nginx - 通配符域和通配符子域
- c++ - 使用 range-v3 操作基础范围
- azure - Azure RM VM 硬盘
- firebase - 如何使用 Firebase 云功能从 http 请求中获取数据?