'Extract ticketcorner event seat prices from a venue map
I want to use beautifulsoup to extract data from a tooltipster that is hovering over a map. Once it finds a point with information, it has to extract three different pieces of information. If it doesn't find anything it should start from the beginning again (tried using try and except for this). If it finds something, it should append it to a list and after print it. At the moment it does not extract anything and I have tried a couple of things.
In the screenshot, you see the information I'm looking to extract:
The page is this: Page
and my code is:
details = []
# Mouse Hover over the concert map and find the empty seats to extract the data.
for x in range(-250, 250, 10):
for y in range(-250, 250, 10):
actions = ActionChains(driver)
actions.move_to_element_with_offset(driver.find_element(by=By.XPATH,
value='//*[@id="seatmap-tab"]/div[2]/div/div/section/div[2]/div[2]/div[2]/div/div[2]'),0, 0)
actions.move_by_offset(x, y).perform()
time.sleep(.4)
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
try:
for div in soup.find_all(class_='sm-tooltip-title theme-headline-color'):
for span in soup.find_all(class_='sm-tooltip-name theme-headline-color'):
for div in soup.find_all(class_='sm-tooltip-name theme-headline-color'):
details.append(tr.text.strip().replace('\n', ' '))
except:
break
print(details)
Solution 1:[1]
When I approach a task like this I usually go straight for the API (here: https://api.eventim.com/seatmap/api/SeatMapHandler), instead of trying to parse the output.
In your case that would require to obtain the necessary request parameters, first. Something like this works for me:
import requests
import json
from bs4 import BeautifulSoup
import re
from urllib.parse import urlencode
url = "https://www.ticketcorner.ch/event/art-on-ice-2023-hallenstadion-12731448/"
headers = {
'User-Agent': 'Not gonna tell',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
'Accept-Encoding': 'gzip, deflate, br',
'Content-Type': 'application/json',
}
# use BeautifulSoup to extract the <script> with the necessary request parameters
soup: BeautifulSoup = BeautifulSoup(requests.get(url, headers=headers,).text)
signature_json: dict = json.loads(soup.find('script', text=re.compile('seatmapOptions')).text)
# extract the parameters as dict to easily query them
parameters_list: list[list] = signature_json.get('seatmapOptions').get('additionalRequestParams').split('&')
parameters = dict()
for parameter in parameters_list:
if len((item := parameter.split('='))) > 1:
parameters[item[0]] = item[1]
# build the request URL
stub = f'https://api.eventim.com/seatmap/api/SeatMapHandler?smcVersion=v6.1&version=v6.2.11&cType=web&cId=8&'
event_parameters = {
'evId': '12731448',
'a_holds': '1',
'a_rowRules': '1',
'a_systemId': '1',
'a_promotionId': parameters.get('a_promotionId'),
'a_sessionId': parameters.get('a_sessionId'),
'timestamp': parameters.get('timestamp'),
'expiryTime': parameters.get('expiryTime'),
'chash': parameters.get('chash'),
'signature': parameters.get('signature'),
'fun': 'json',
'areaId': '0',
}
data: dict = requests.get(stub + urlencode(event_parameters)).json()
This is just a very basic example and you will probably have to add other query parameters to get seat information, eg blockId. The idea stays the same, though: get the necessary requerst parameter to authenticate against the API and then query the endpoint directly.
You might also get blocked at some point if your activity seems malicious...
Solution 2:[2]
Pointers cannot menaingfully be saved.
You have to save what they point to and somehow identify it so that the pointer can be replaced by a suitable "this one" in the file.
Then when you find a "this one" in the file you first need to find within the file what it refers to, load that and write its address into the pointer variable you want to restore.
Note that at this point, the address/number stored inside the pointer is almost guaranteed to be different than before saving. But what it points to has the same content, which is what you actually want when "storing a pointer".
The general idea I described is a concept called "persistence" for the special case of pointers. The special aspect of pointers is that you do not actually want to store the (basically) number inside, it is necessary to represent the semantic of "this one".
The details of which (proprietary file syntax, database, persistence libraries...) require some choices for your special case, which you have to decide; instead of letting me put any example here in detail which would in some way or other most likely not match what you need.
Solution 3:[3]
You cannot do that, because a pointer's contents has no meaning per se.
Usually, this problem can be tackled by replacing each pointer with either a fixed or variable-sized field, or adding "internal pointers" if the filesize and memory pointer sizes are compatible.
typedef struct
{
char* name;
int played;
int win;
} Player;
could become, in the file:
0000 4 bytes (played)
0004 4 bytes (win)
0008 2 bytes (length of name)
000A .. bytes (name)
And you would read it by fread()ing the first 10 bytes, converting them into a temporary structure similar to your Player:
typedef struct
{
int32_t played;
int32_t win;
int16_t playerLength;
} FilePlayer;
at that point you would allocate tmp.playerLength + 1 bytes and read tmp.playerLength' worth of bytes from the file, adding a zero since C strings are zero-terminated, and assign this chunk of memory to newPlayer->name.
Or you could gather all fixed-size records at the beginning of your save-file, so they are easily readable in a loop, and add the variable-length strings at the end. Then, each fixed-record item that points to a variable-length object would have to become an offset into the file itself.
Or you could go for a human-parsable file, where each line of text is a field. This also allows easy inspection and manipulation of the file with third-party editors. In that case you could use ancillary functions to read int, char*, and so on, and:
record = malloc(sizeof Player);
if (NULL == record) {
fclose(fp);
return failure("memory error");
}
if (NULL == (record->name = readString(fp))) {
fclose(fp);
return failure("error reading name");
}
if (-1 == (record->played = readInt(fp))) {
fclose(fp);
return failure("error reading record");
}
if (-1 == (record->win = readInt(fp))) {
fclose(fp);
return failure("error reading record");
}
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dan Atkinson |
| Solution 2 | |
| Solution 3 | LSerni |
