Данные действительно зашифрованы. Если вы посмотрите на JS файлы, которые являются частью веб-сайта, вы можете найти этот конкретный файл , который содержит функцию, используемую для дешифрования данных. Все это делается в Javascript, поэтому у вас есть 2 варианта:
- использовать beautifulsoup , чтобы очистить страницу, перекодировать функцию расшифровки javascript в python
- используйте безголовый браузер, такой как селен
Используя первый вариант (перекодирование функции шифрования в python), вот как вы может сделать это:
import requests
from bs4 import BeautifulSoup
import base64
import json
url = "https://marketchameleon.com/Overview/BAX/Earnings/Earnings-Dates"
session = requests.Session()
r = session.get(url)
soup = BeautifulSoup(r.text, "html.parser")
key = session.cookies.get_dict()["v1"]
encryptedDivs = [ i["cipherxx"] for i in soup.find_all("div") if i.get("cipherxx")]
unencrypted = []
for div in encryptedDivs:
encryptedData = base64.b64decode(div)
cipher = "".join([
chr(encryptedData[i])
for i in range(0,len(encryptedData),2)
])
data = ""
for i in range(0, len(cipher)):
c_num = ord(cipher[i])
k_num = ord(key[i % len(key)])
c2 = c_num ^ k_num
data += chr(c2)
unencrypted.append(data)
# unencrypted[0] is the header div with some info about stock price etc...
# unencrypted[1] is the first table
# lets parse the second table unencrypted[2]
soup = BeautifulSoup(unencrypted[2], "html.parser")
tbody = soup.find("tbody").findAll("tr", recursive=False)
thead = soup.find("thead").findAll("tr", recursive=False)
table2 = [
{
"Date": t[0].text.strip(),
"Time": t[1].text.strip(),
"Period": t[2].text.strip(),
"Conference Call": t[3].text.strip(),
"Price Effect" : t[4].find("span").text if t[4].find("span") else t[4].text.strip(),
"Implied Straddle": t[5].text.strip(),
"Closing Price": t[6].text.strip(),
"Opening Gap": t[7].text.strip(),
"Drift Since": t[8].text.strip(),
"Range Since": t[9].text.strip(),
"Price Change 1 Week Before":t[10].text.strip(),
"Price Change 1 Week After": t[11].text.strip()
}
for t in (t.findAll('td', recursive=False) for t in tbody)
if len(t) >= 11
]
print(json.dumps(table2, indent=4, sort_keys=True))
Обратите внимание, что ключ шифрования находится в Cook ie с именем v1
(поэтому вам нужно requests.Session()
)
Часть шифрования
Это XOR шифрование . Это XOR значения данных с ключом (в этом случае ключ хранится в кулинарии ie). Для расшифровки вам просто нужно XOR шифр с ключом, чтобы получить исходные данные.
Самый эффективный способ объяснить это - использовать пример:
- data это строка "HELLO"
- ключ это строка "97523022"
"H" "E" "L" "L" "O"
72 69 76 76 79
01001000 01000101 01001100 01001100 01001111
"9" "7" "5" "2" "3"
57 55 53 50 51
00111001 00110111 00110101 00110010 00110011
01001000 01000101 01001100 01001100 01001111
XOR 00111001 00110111 00110101 00110010 00110011
==> 01110001 01110010 01111001 01111110 01111100
113 114 121 126 124
HEX \x71 \x72 \x79 \x7E \x7C
complete with 0s :
HEX \x71\x00 \x72\x00 \x79\x00 \x7E\x00 \x7C\x00
encode \x71\x00\x72\x00\x79\x00\x7E\x00\x7C\x00 to base64
which gives : 'cQByAHkAfgB8AA=='
попробуйте этот код для расшифровки (тот же код, что и код в начале вопроса):
key = "97523022"
payload = "cQByAHkAfgB8AA=="
data = base64.b64decode(payload)
cipher = "".join([
chr(data[i])
for i in range(0,len(data),2)
])
data = ""
for i in range(0, len(cipher)):
c_num = ord(cipher[i])
k_num = ord(key[i % len(key)])
c2 = c_num ^ k_num
data += chr(c2)
print(data)
Вывод:
HELLO
Вы также можете проверить эту ссылку и эту вики если вы заинтересованы