MIT*_*THU 10 python beautifulsoup web-scraping python-3.x
我已经创建了一个脚本来从网页上抓取name
并email
寻址。当我运行脚本时,我得到了name
相应的信息,但是在email
这种情况下,我得到了aeccdcd7cfc0eedadcc783cdc1dc80cdc1c3
。email
每次运行脚本时,我得到的字符串(而不是字符串)都会更改。
到目前为止,我已经尝试过:
import requests
from bs4 import BeautifulSoup
url = "https://www.seafoodsource.com/supplier-directory/Tri-Cor-Flexible-Packaging-Inc"
res = requests.get(url,headers={"User-Agent":"Mozilla/5.0"})
soup = BeautifulSoup(res.text,'lxml')
name = soup.select_one("[class$='-supplier-view-main-container'] > h1").text
email = soup.select_one("[class='__cf_email__']").get("data-cfemail")
print(f'{"Name: "}{name}\n{"Email: "}{email}')
Run Code Online (Sandbox Code Playgroud)
电流输出:
Name: Tri-Cor Flexible Packaging Inc
Email: aeccdcd7cfc0eedadcc783cdc1dc80cdc1c3
Run Code Online (Sandbox Code Playgroud)
预期产量:
Name: Tri-Cor Flexible Packaging Inc
Email: bryan@tri-cor.com
Run Code Online (Sandbox Code Playgroud)
PS我不追求任何与任何浏览器模拟器相关的解决方案,例如硒。
如何使用请求从该页面获取该电子邮件?
您必须解码电子邮件。
import requests
from bs4 import BeautifulSoup
def cfDecodeEmail(encodedString):
r = int(encodedString[:2],16)
email = ''.join([chr(int(encodedString[i:i+2], 16) ^ r) for i in range(2, len(encodedString), 2)])
return email
url = "https://www.seafoodsource.com/supplier-directory/Tri-Cor-Flexible-Packaging-Inc"
res = requests.get(url,headers={"User-Agent":"Mozilla/5.0"})
soup = BeautifulSoup(res.text,'lxml')
name = soup.select_one("[class$='-supplier-view-main-container'] > h1").text
email = cfDecodeEmail(soup.select_one("[class='__cf_email__']").get("data-cfemail"))
print(f'{"Name: "}{name}\n{"Email: "}{email}')
Run Code Online (Sandbox Code Playgroud)
输出:
Name: Tri-Cor Flexible Packaging Inc
Email: bryan@tri-cor.com
Run Code Online (Sandbox Code Playgroud)
简短的答案是您必须解码电子邮件字符串,因为它被混淆了。
以下是您必须对从Seafoodsource.com获得的电子邮件字符串进行解码的原因。
网站Seafoodsource.com使用的是Cloudflare,这是一家美国公司,向客户提供网站安全性,DDoS缓解措施和其他服务。
我通过ping Seafoodsource.com来确定该站点正在使用Cloudflare,该IP地址返回104.24.19.99。根据ARIN(美国互联网号码注册机构),此IP地址属于netblock 104.16.0.0-104.31.255.255,该网络块已注册到Cloudflare。
汤中的字符串cf_email也表明该电子邮件地址受Cloudflare(CF)保护。另一个指示是此警告消息,当您在查看页面源时单击受保护的链接时会显示该警告消息。
Cloudflare电子邮件地址混淆可通过隐藏来自电子邮件收割者和其他漫游器的目标网站上显示的电子邮件地址来帮助防止垃圾邮件,但普通站点访问者可以看到该电子邮件。
在此保护下,电子邮件地址将变成十六进制编码的一系列可变长度的字节,具体取决于电子邮件地址的长度。
值得注意的是,这种编码方法并不是设计用于安全地加密电子邮件地址,因为它在密码上较弱,而只是设计为使正在搜索HTML代码内的mailto:链接的非智能Web抓取工具混淆。换句话说,此编码方法用于混淆电子邮件地址,但不能完全强制执行其保密性。
您问题中的编码电子邮件地址为:
aeccdcd7cfc0eedadcc783cdc1dc80cdc1c3
此电子邮件地址的第一个字节为ae或十六进制0xae。该字节是一个密钥,用于通过将密钥与每个后续字节按位进行XOR来加密和解密其余字节。
例如:
0xae ^ 0xcc是十六进制62,将ASCII 转换为b
0xae ^ 0xdc为十六进制72,将ASCII 转换为r
0xae ^ 0xd7是十六进制79,将ASCII 转换为y
0xae ^ 0xcf是十六进制61,其转换为一个以ASCII
0xae ^ 0xc0是十六进制6e,将ASCII 转换为n
这拼写为bryan,这是已解码电子邮件地址的第一部分。
此代码中发生按位异或:
chr(int(encoded_string [i:i + 2],16)^ base_16)
让我进一步解释:
编码字符串的第一个字节是密码密钥,在这种情况下为ae或0xae。
如果将0xae转换为十进制,则为174。
当我们将下一个字节0xcc转换为十进制时,它变为204。
让我们使用按位运算符^转换这些小数。
^按位异或
返回两个整数的按位XOR结果。
first_byte = 174 # ae
second_byte = 204 # cc
xor_decimal = first_byte ^ second_byte
print (xor_decimal)
# outputs
98
Run Code Online (Sandbox Code Playgroud)
让我们将这些十进制数转换为十六进制数(以16为基数)。我们可以在Python中使用内置函数“ hex”来完成此操作。
first_byte = 174 # ae
second_byte = 204 # cc
xor_decimal = first_byte ^ second_byte
print (hex)xor_decimal)
# outputs
62
Run Code Online (Sandbox Code Playgroud)
正如我之前提到的十六进制62,它以ASCII格式转换为b
让我们看一下编码字符串中的下一个字节迭代。
first_byte = 174 # ae
next_byte = 220 # dc
xor_decimal = first_byte ^ next_byte
print (hex)xor_decimal)
# outputs
72
Run Code Online (Sandbox Code Playgroud)
正如我之前提到的十六进制72,它以ASCII格式转换为r
我觉得展示如何将十六进制字符串转换为十进制很重要。
# without the 0x prefix
decimal = int('ae', 16)
print (decimal)
# outputs
174
# with the 0x prefix
decimal = int('0xae', 0)
print (decimal)
# outputs
174
Run Code Online (Sandbox Code Playgroud)
混淆后的电子邮件地址的ASCII文本到十六进制的转换:
ASCII电子邮件地址:bryan@tri-cor.com
十六进制电子邮件地址:62 72 79 61 6e 40 74 72 69 2d 63 6f 72 2e 63 6f 6d
我们可以在Python中使用内置函数bytearray来解码此十六进制字符串:
hex_string = '62 72 79 61 6e 40 74 72 69 2d 63 6f 72 2e 63 6f 6d'
ascii_conversion = bytearray.fromhex(hex_string).decode()
print (ascii_conversion)
# outputs
bryan@tri-cor.com
Run Code Online (Sandbox Code Playgroud)
混淆后的电子邮件地址的ASCII文本到十进制的转换:
ASCII电子邮件地址:bryan@tri-cor.com
十进制电子邮件地址:98 114 121 97 110 64 116 114 105 45 99 111 114 46 99 111 109
如果我们在小数点电子邮件地址的开头加上小数点174,即混淆字符串中的ae:
十进制电子邮件地址:174 98 114 121 97 110 64 116 114 105 45 99 111 114 46 99 111 109
ASCII电子邮件地址:®bryan@tri-cor.com
看来®是ASCII字符,用作问题中混淆字符串的密码密钥。
如果我不提到二进制数和XOR操作,我将不知所措。
首字节转换:
第二字节转换:
我们可以对上面的二进制数字执行相同的^按位异或运算:
# the notation 0b in front of the number is used to express that the value is
# a binary literal
first_byte_binary = 0b10101110
second_byte_binary = 0b11001100
xor_binary = first_byte_binary ^ second_byte_binary
print (bin(xor_binary))
# outputs
0b1100010
print (xor_binary)
# outputs
98
print (hex(xor_binary))
# outputs
0x62
ascii_conversion = bytearray.fromhex(hex(xor_binary)[2:]).decode()
print (ascii_conversion)
# outputs
b
Run Code Online (Sandbox Code Playgroud)
这是解码Cloudflare混淆电子邮件地址的方法。
import requests
from bs4 import BeautifulSoup
url = "https://www.seafoodsource.com/supplier-directory/Tri-Cor-Flexible-Packaging-Inc"
raw_html = requests.get(url,headers={"User-Agent":"Mozilla/5.0"})
soup = BeautifulSoup(raw_html.text,'lxml')
company_information = []
def get_company_name(soup):
company_name = soup.find('li', {'class': 'active'}).text
company_information.append(company_name)
return
def decode_cloudflare_protected_email(encoded_string):
# converting the encoding string to int base 16
base_16 = int(encoded_string[:2], 16)
decoded_email = ''.join([chr(int(encoded_string[i:i+2], 16) ^ base_16) for i in range(2, len(encoded_string), 2)])
company_information.append(decoded_email)
return
get_company_name(soup)
encoded_email = soup.select_one("[class='__cf_email__']").get("data-cfemail")
decode_cloudflare_protected_email(encoded_email)
print (company_information)
# outputs
['Tri-Cor Flexible Packaging Inc', 'bryan@tri-cor.com']
Run Code Online (Sandbox Code Playgroud)
如果您对探索XOR加密的兴趣超过我建议的xortool,那是Aleksei Hellman的Github项目。