如何在Python中按文本单击没有文本的链接
我正试图从vivino.com上获取葡萄酒数据,并使用selenium将其自动化,尽可能多地获取数据。我的代码如下所示:如何在Python中按文本单击没有文本的链接,python,selenium,selenium-webdriver,web-scraping,Python,Selenium,Selenium Webdriver,Web Scraping,我正试图从vivino.com上获取葡萄酒数据,并使用selenium将其自动化,尽可能多地获取数据。我的代码如下所示: import time from selenium import webdriver browser = webdriver.Chrome('C:\Program Files (x86)\chromedriver.exe') browser.get('https://www.vivino.com/explore?e=eJwFwbEOQDAUBdC_uaNoMN7NZhQ
import time
from selenium import webdriver
browser = webdriver.Chrome('C:\Program Files (x86)\chromedriver.exe')
browser.get('https://www.vivino.com/explore?e=eJwFwbEOQDAUBdC_uaNoMN7NZhQLEXmqmiZaUk3x987xkVXRwLtAVcLLy7qE_tiN0Bz6FhcV7M4s0ZkkB86VUZIL9l4kmyjW4ORmbo0nTTPVDxlkGvg%3D&cart_item_source=nav-explore') # Vivino Website with 5 wines for now (simple example). Plan to scrape around 10,000 wines
lenOfPage = browser.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
match=False
while(match==False):
lastCount = lenOfPage
time.sleep(7)
lenOfPage = browser.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
if lastCount==lenOfPage:
match=True
这将打开一个包含5种葡萄酒的网站并向下滚动。现在我想一个接一个地点击葡萄酒的超链接,以获取有关其价格、葡萄酒葡萄种类等的信息。因此,基本上我的脚本将尝试向下滚动,允许在页面上显示尽可能多的葡萄酒,然后点击第一个超链接,获取更多信息并返回。然后,该过程将重复。我不认为这是一个有效的策略,但这就是我到目前为止提出的
我的问题是维维诺网站的超链接。href链接附近没有文本,允许我使用按链接查找元素\u text功能:
<a class="anchor__anchor--2QZvA" href="/weingut-r-a-pfaffl-austrian-cherry-zweigelt/w/1261542?year=2018&price_id=23409078&cart_item_source=direct-explore" target="_blank">
请您建议如何点击超链接后没有文本的含硒葡萄酒?我在网上搜索时没有找到正确的答案。提前感谢我的意思是,使用硒,你做的工作比你必须做的多得多。在访问该页面时,我用谷歌Chrome的开发工具记录了我的网络流量,我看到我的浏览器向RESTAPI发出了一个HTTP GET请求,该请求的响应是JSON,包含了您可能想要的所有葡萄酒/价格信息。所以,你不需要做任何刮擦。只需使用所需的查询字符串参数和正确的头来模拟GET请求。restapi似乎只关心
用户代理
头,这很简单
F12
键打开Google Chrome开发工具菜单。
单击网络
选项卡XHR
。这只会
在日志中显示XHR(XmlHttpRequest)请求。我们对……感兴趣
特别是这些请求,因为是通过XHR请求
API通常是制作的。现在它应该是这样的:explore?…
开头的那个感兴趣,所以我们点击它
标题
选项卡General
区域下,您可以看到请求URL
,它是我们向其发出请求的REST API端点的URL。此URL可能相当长,因为它通常还包含查询字符串参数(这些参数是explore?
之后的键值对,如country\u code=DE
或currency\u code=EUR
。它们之间用和分隔)。查询字符串参数很重要,因为它们包含有关要应用于查询的某些筛选器的信息。在我的代码示例中,我已将它们从RESTAPI端点URL中删除,并将它们移动到params
字典中。这一步不是必需的——您也可以将它们留在URL中,但我发现这样更容易阅读和修改。查询字符串参数也很重要,因为有时某些API会期望某些参数出现在请求中,或者它们会期望它们具有某些值——换句话说,一些API对其查询字符串参数非常挑剔,如果您以API不期望的方式移除或篡改它们,API会说您的请求没有正确表述
在常规
区域中,您还可以看到请求方法
,在本例中是GET
。这告诉我们,我们的浏览器发出了HTTP GET请求。并非所有API端点都工作相同,有些端点需要HTTP POST等
状态代码
告诉我们服务器发回了什么状态代码<代码>200
表示一切正常。你可以了解更多关于
让我们看一下响应标题
区域。此区域包含发出请求后服务器发回的所有响应头。对于浏览器来说,设置cookie或了解如何解释服务器发送回的数据等方面,这些都很有用
请求标题
区域包含浏览器发出请求时发送到服务器的所有标题。通常,最好复制所有这些键值对,并将它们转换为Python字典标题
,因为这样可以确保Python脚本发出与浏览器完全相同的请求。然而,通常,我喜欢尽可能地减少这一点。我知道许多API非常关心用户代理
字段,所以通常我会保留该字段,但有时它们也关心引用者
。当您使用不同的API时,您必须通过反复试验确定API关心哪些请求头。这个API恰好只关心用户代理
洛杉矶
def main():
import requests
url = "https://www.vivino.com/api/explore/explore"
params = {
"country_code": "DE",
"currency_code": "EUR",
"grape_filter": "varietal",
"min_rating": "3.5",
"order_by": "ratings_average",
"order": "desc",
"page": "1",
"price_range_max": "30",
"price_range_min": "7",
"wine_type_ids[]": "1"
}
headers = {
"user-agent": "Mozilla/5.0"
}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
records = response.json()["explore_vintage"]["records"]
for record in records:
name = record["vintage"]["name"]
price = record["price"]["amount"]
currency = record["price"]["currency"]["code"]
print(f"\"{name}\" - Price: {price} {currency}")
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
"Varvaglione Cosimo Varvaglione Collezione Privata Primitivo di Manduria 2015" - Price: 21.9 EUR
"Masseria Borgo dei Trulli Mirea Primitivo di Manduria 2019" - Price: 19.9 EUR
"Vigneti del Salento Vigne Vecchie Primitivo di Manduria 2016" - Price: 22.95 EUR
"Vigneti del Salento Vigne Vecchie Leggenda Primitivo di Manduria 2016" - Price: 17.87 EUR
"Varvaglione Papale Linea Oro Primitivo di Manduria 2016" - Price: 18.85 EUR
"Caballo Loco Grand Cru Apalta 2014" - Price: 27.9 EUR
"Luccarelli Il Bacca Old Vine Primitivo di Manduria 2016" - Price: 20.9 EUR
"Mottura Stilio Primitivo di Manduria 2018" - Price: 12.89 EUR
"Caballo Loco Grand Cru Maipo 2015" - Price: 24.81 EUR
"Lorusso Michele Solone Primitivo 2017" - Price: 21.39 EUR
"Château Purcari Negru de Purcari 2017" - Price: 29.8 EUR
"San Marzano 60 Sessantanni Limited Edition Old Vines Primitivo di Manduria 2016" - Price: 22.85 EUR
"San Marzano 60 Sessantanni Old Vines Primitivo di Manduria 2016" - Price: 20.9 EUR
"San Marzano 60 Sessantanni Old Vines Primitivo di Manduria 2017" - Price: 17.775 EUR
"Lenotti Amarone della Valpolicella Classico 2015" - Price: 27.95 EUR
"Zeni Cruino Rosso Veronese 2015" - Price: 22.9 EUR
"Masseria Pietrosa Palmenti Primitivo di Manduria Vigne Vecchie 2016" - Price: 25 EUR
"Ravazzi Prezioso 2016" - Price: 29.95 EUR
"Nino Negri Sfursat Carlo Negri 2017" - Price: 23.89 EUR
"Quinta do Paral Reserva Tinto 2017" - Price: 29.24 EUR
"Wildekrans Barrel Select Reserve Pinotage 2016" - Price: 29.9 EUR
"Caballo Loco Grand Cru Limarí 2016" - Price: 27.9 EUR
"San Marzano F Negroamaro 2018" - Price: 16.9 EUR
"Atlan & Artisan 8 Vents Mallorca 2018" - Price: 19 EUR
"Schneider Rooi Olifant Red 2017" - Price: 19.5 EUR
>>>
record["vintage"]["year"]
record["vintage"]["wine"]["region"]["name"]
record["vintage"]["wine"]["region"]["country"]["name"]
record["vintage"]["wine"]["taste"]["structure"]["acidity"]
record["vintage"]["wine"]["taste"]["structure"]["intensity"]
record["vintage"]["wine"]["taste"]["structure"]["sweetness"]
record["vintage"]["wine"]["taste"]["structure"]["tannin"]
record["vintage"]["wine"]["style"]["grapes"][0]["name"] # 0th grape information
record["vintage"]["wine"]["winery"]["name"]
links = browser.find_elements_by_css_selector('div.cleanWineCard__cleanWineCard--tzKxV.cleanWineCard__row--CBPRR > a')
for a in links:
a.click()
# grab information
# sleep a bit
#...
from bs4 import BeautifulSoup
import requests
import time, os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
chromedriver = "C:\\Program Files\Google\Chrome\Application\chromedriver" # path to the chromedriver executable
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)
driver.get('https://www.vivino.com/explore?e=eJwFwbEOQDAUBdC_uaNoMN7NZhQLEXmqmiZaUk3x987xkVXRwLtAVcLLy7qE_tiN0Bz6FhcV7M4s0ZkkB86VUZIL9l4kmyjW4ORmbo0nTTPVDxlkGvg%3D&cart_item_source=nav-explore')
#browser.get('https://www.vivino.com/explore?e=eJwFwbEOQDAUBdC_uaNoMN7NZhQLEXmqmiZaUk3x987xkVXRwLtAVcLLy7qE_tiN0Bz6FhcV7M4s0ZkkB86VUZIL9l4kmyjW4ORmbo0nTTPVDxlkGvg%3D&cart_item_source=nav-explore') # Vivino Website with 5 wines for now (simple example). Plan to scrape around 10,000 wines
lenOfPage = driver.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
list= []
match=False
while(match==False):
lastCount = lenOfPage
time.sleep(7)
lenOfPage = driver.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
match=True
soup = BeautifulSoup(driver.page_source, 'html.parser')
for a in soup.find_all('a', href=True):
print( a['href'] )
links = driver.find_elements_by_xpath('//*[@href]')
for i in links:
print(i.get_attribute('href'))