如何抓取ajax返回的网页内容?
Posted
技术标签:
【中文标题】如何抓取ajax返回的网页内容?【英文标题】:How to scrape web page content that's returned by ajax? 【发布时间】:2020-02-17 01:39:45 【问题描述】:这是我要抓取的页面:https://www.racing.com/form/2018-11-06/flemington/race/7/results 比赛结果信息不在源代码中。
我在 Chrome DevTools 中尝试过,但没有找到包含结果的响应数据。
以下是源代码中的一些代码:
ng-controller="formTabResultsController"
ng-init="meet=5149117;race=7;init();" ajax-loader="result"
我认为结果被返回并保存在“结果”结构中,因为有很多这样的:“result.PrizeMoney”“result.Record”。
那么如何用 Python 获取结果的数据呢?谢谢。
【问题讨论】:
【参考方案1】:此站点在https://graphql.rmdprod.racing.com
上使用GraphQL API。 API 密钥需要通过标头发送并检索到here。
curl、sed 和 jq 的示例:
api_key=$(curl -s "https://www.racing.com/layouts/app.aspx" | \
sed -nE 's/.*headerAPIKey:\s*"(.*)"/\1/p')
curl -s "https://www.racing.com/layouts/app.aspx"
query='query GetMeeting($meetCode: ID!)
getMeeting(id: $meetCode)
id
trackName
date
railPosition
races
id
raceNumber
status
tempo
formRaceEntries
id
raceEntryNumber
horseName
silkUrl
jockeyName
trainerName
scratched
speedValue
barrierNumber
horse
name
fullName
colour
'
variables=' "meetCode": 5149117 '
curl -G 'https://graphql.rmdprod.racing.com' \
--data-urlencode "query=$query" \
--data-urlencode "variables=$variables" \
-H "X-Api-Key: $api_key" | jq '.'
将python 与python-requests 一起使用:
import requests
import re
import json
r = requests.get("https://www.racing.com/layouts/app.aspx")
api_key = re.search(".*headerAPIKey:\s*\"(.*)\"", r.text).group(1)
query= """query GetMeeting($meetCode: ID!)
getMeeting(id: $meetCode)
id
trackName
date
railPosition
races
id
raceNumber
status
tempo
formRaceEntries
id
raceEntryNumber
horseName
silkUrl
jockeyName
trainerName
scratched
speedValue
barrierNumber
horse
name
fullName
colour
"""
payload =
"variables": json.dumps(
"meetCode": 5149117
),
"query": query
r = requests.get(
'https://graphql.rmdprod.racing.com',
params = payload,
headers =
"X-Api-Key": api_key
)
print(r.json())
【讨论】:
你太棒了!非常感谢。你做这个任务的程序是什么?我的意思是我花了一天时间但没有得到任何线索,显然是新手。 @IanJay 我已经检查了 chrome 控制台中的网络日志选项卡。 @IanJay 您也可以使用一些introspection query 来检查您可以查询的内容:query __schema queryType name fields namemutationType name fields name
非常感谢。这个查询似乎只得到了部分结果,不包括排名、速度等。我在下面查看了这个人的答案(@nicolas),我认为这是两个不同的请求,一个是关于马的信息,另一个是关于比赛结果。我说的对吗?
@IanJay 您可以使用 graphql API 获取所有这些字段。安装npm install -g get-graphql-schema
和get-graphql-schema https://graphql.rmdprod.racing.com -h "X-Api-Key=da2-akkuiub3brhahc7nab2msruddq" -j > schema.json
。然后您可以检查所有可用的字段/对象/列表【参考方案2】:
Chrome 开发工具显示对其 API 的调用
import re
import requests
import json
resp = requests.get('https://api.racing.com/v1/en-au/race/results/5149117/7/?callback=angular.callbacks._b')
# Returned JSONP so we remove the function call: keep only what is between ()
m = re.search(r'\((.*)\)', resp.text, flags=re.S)
data = json.loads(m.group(1))
print(data.keys())
# dict_keys(['race', 'resultCollection', 'exoticCollection'])
print(data['resultCollection'][0])
# 'position': 'at400m': 12, 'at800m': 20, 'finish': 1, 'positionAbbreviation': '1st', 'positionDescription': '', 'positionType': 'Finished', 'scratched': False, 'winningTime': 20117, 'margin': None, 'raceEntryNumber': 23, 'number': 23, 'barrierNumber': 19, 'isDeadHeat': False, 'weight': '51kg', 'rating': 'handicapRating': 109, 'ratingProgression': 0, 'prizeMoney': 4000000.0, 'horse': 'fullName': 'Cross Counter (GB)', 'code': 5256710, 'urlSegment': 'cross-counter-gb', 'silkUrl': '//s3-ap-southeast-2.amazonaws.com/racevic.silks/bb/12621.png', 'age': 5, 'sex': 'Gelding', 'colour': 'Bay', 'sire': 'Teofilo (IRE)', 'dam': 'Waitress (USA)', 'totalPrizeMoney': '$4,576,227', 'averagePrize': '$508,470', 'trainer': 'fullName': None, 'shortName': 'C.Appleby', 'code': 20658431, 'urlSegment': 'charlie-appleby-gb', 'jockey': 'fullName': 'K.McEvoy', 'shortName': 'K.McEvoy', 'code': 25602, 'urlSegment': 'kerrin-mcevoy', 'allowedClaim': 0.0, 'apprentice': False, 'gear': 'hasChanges': True, 'gearCollection': ['changeDate': '2018-11-02T00:00:00', 'currentChange': True, 'description': 'Bandages (Front): On', 'name': 'Bandages (Front)', 'status': 'On', 'comments': None, 'changeDate': '2018-08-01T00:00:00', 'currentChange': False, 'description': 'Ear Muffs (Pre-Race Only)', 'name': 'Ear Muffs (Pre-Race Only)', 'status': 'On', 'comments': None, 'changeDate': '2018-08-01T00:00:00', 'currentChange': False, 'description': 'Lugging Bit', 'name': 'Lugging Bit', 'status': 'On', 'comments': 'Rubber ring bit', 'changeDate': '2018-08-01T00:00:00', 'currentChange': False, 'description': 'Cross-over Nose Band', 'name': 'Cross-over Nose Band', 'status': 'On', 'comments': None], 'currentGearCollection': None, 'odds': 'priceStart': '$9.00', 'parimutuel': 'returnWin': '12', 'returnPlace': '4.40', 'isFavouriteWin': False, 'fluctuations': 'priceOpening': '$10.00', 'priceFluc': '$10.00', 'comment': 'Bit Slow Out Settled Down near tail lucky to avoid injured horse was checked though 12l bolting Turn Straightened Up Off Mid-Field 7-8l gets Clear 400 and charged home to score. big win # very good from back', 'extendedApiUrl': '/v1/en-au/form/horsestat/5149117/7/5256710', 'extendedApiUrlMobile': '/v1/en-au/form/horsestatmobile/5149117/7/5256710', 'last5': ['-', '4', '3', '-', '4']
【讨论】:
【参考方案3】:另一种方法是使用这些参数(可通过浏览器中的“开发人员”选项卡发现),而不使用正则表达式:
import requests
import json
url = 'https://graphql.rmdprod.racing.com/?query=query%20GetMeeting($meetCode:%20ID!)%20%7BgetMeeting(id:%20$meetCode)%7Bid,trackName,date,railPosition,races%7Bid,raceNumber,status,tempo,formRaceEntries%7Bid,raceEntryNumber,horseName,silkUrl,jockeyName,trainerName,scratched,speedValue,barrierNumber%7D%7D%7D%7D&variables=%7B%20%22meetCode%22:%205149117%20%7D'
headers =
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Content-Type": "application/json",
"X-Api-Key": "da2-akkuiub3brhahc7nab2msruddq"
resp = requests.get(url,headers=headers)
data= json.loads(resp.text) # or data = json.decoder(resp.text)
data
【讨论】:
以上是关于如何抓取ajax返回的网页内容?的主要内容,如果未能解决你的问题,请参考以下文章