在 python 中使用 selenium 从动态网站获取数据:如何发现数据库查询的完成方式?

Posted

技术标签:

【中文标题】在 python 中使用 selenium 从动态网站获取数据:如何发现数据库查询的完成方式?【英文标题】:Using selenium in python to get data from dynamic website: how to discover the way databases querys are done? 【发布时间】:2019-02-17 14:39:09 【问题描述】:

我之前有一些编码经验,但不是专门针对 Web 应用程序的。我的任务是从这个网站获取数据:http://www.b3.com.br/pt_br/market-data-e-indices/servicos-de-dados/market-data/consultas/mercado-de-derivativos/precos-referenciais/taxas-referenciais-bm-fbovespa/

它们每天都可用。我在 Python 中使用过 selenium,到目前为止效果很好:我可以获取整个表,将其存储在 pandas 数据框中,然后存储到 mysql 数据库等。问题是:网站的结果总是一样的!

这是我的代码:

from selenium import webdriver
from bs4 import BeautifulSoup as bs
import time
def GetDataFromWeb(day, month, year):
options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('window-size=1920x1080')
#had to use these two below because of webdriver crashing issues
options.add_argument('no-sandbox')
options.add_argument('disable-dev-shm-usage')

driver = webdriver.Chrome(chrome_options=options)

driver.get("http://www.b3.com.br/pt_br/market-data-e-indices/servicos-de-dados/market-data/consultas/mercado-de-derivativos/precos-referenciais/taxas-referenciais-bm-fbovespa/")

#the table is on an iframe
iframe = driver.find_element_by_id("bvmf_iframe")
driver.switch_to.default_content()
driver.switch_to.frame(iframe)

#getting to the place where I should input the data
date = driver.find_element_by_id("Data")
date.send_keys("/".join((str(day),str(month),str(year))))
date = driver.find_element_by_tag_name("button").click()

#I have put this wait just to be sure it doesn't try to get info from an unloaded page
time.sleep(5)

page = bs(driver.page_source,"html.parser")

table = page.find(id='tb_principal1')

headers = ['Dias Corridos', '252','360']

matrix = []
for rows in table.select('tr')[2:]:
    values = []
    for columns in rows.select('td'):
        values.append(columns.text.replace(',','.'))
    matrix.append(values)

df = pd.DataFrame(data=matrix, columns=headers)

driver.close()

#only the first 2 columns are interesting for my purposes
return df.iloc[:,0:2]

无论我向其发送什么输入,此函数生成的表始终相同。它们似乎来自 06/09/2018 的相应日期(月=09,日=06)。我认为主要问题是我不知道对他们的数据库的查询是如何完成的,所以这总是像“默认日期”一样运行。我读过一些人谈论 Ajax 和 javascript 请求,但我不知道是不是这样。我怎么知道?

【问题讨论】:

【参考方案1】:

此代码将起作用(在您的代码中更新了几行)

from selenium import webdriver
from bs4 import BeautifulSoup as bs
import time
import pandas as pd
def GetDataFromWeb(day, month, year):

***#to avoid data error in date handler***
if month < 10:
    month="0"+str(month)
if day < 10:
    day="0"+str(day)

options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('window-size=1920x1080')
#had to use these two below because of webdriver crashing issues
options.add_argument('no-sandbox')
options.add_argument('disable-dev-shm-usage')

driver = webdriver.Chrome(chrome_options=options)

driver.get("http://www.b3.com.br/pt_br/market-data-e-indices/servicos-de-dados/market-data/consultas/mercado-de-derivativos/precos-referenciais/taxas-referenciais-bm-fbovespa/")

#the table is on an iframe
iframe = driver.find_element_by_id("bvmf_iframe")
driver.switch_to.default_content()
driver.switch_to.frame(iframe)

#getting to the place where I should input the data
date = driver.find_element_by_id("Data")
date.clear() ***#to clear auto populated data***
date.send_keys(((str(day),str(month),str(year)))) ***# removed the join part***

driver.find_element_by_tag_name("button").click()

#I have put this wait just to be sure it doesn't try to get info from an unloaded page
time.sleep(50)

page = bs(driver.page_source,"html.parser")

table = page.find(id='tb_principal1')

headers = ['Dias Corridos', '252','360']

matrix = []
for rows in table.select('tr')[2:]:
    values = []
    for columns in rows.select('td'):
        values.append(columns.text.replace(',','.'))
    matrix.append(values)

df = pd.DataFrame(data=matrix, columns=headers)

driver.close()

#only the first 2 columns are interesting for my purposes
return df.iloc[:,0:2]

print GetDataFromWeb(3,9,2018)

它将打印所需日期的匹配数据。

我已添加#以避免日期处理程序中的数据错误

if month < 10:
    month="0"+str(month)
if day < 10:
    day="0"+str(day)

date.clear() #清除自动填充的数据 date.send_keys(((str(day),str(month),str(year)))) #删除了连接部分

请注意,您的代码中的问题是日期和月份字段采用两位数,date.send_keys("/".join((str(day), str(month), str(year)))) 行生成错误,因此选择了系统日期,并且您总是会看到任何输入数据的相同数据。此外,当您单击它选择默认日期的日期时,我们必须首先清除该日期并发送自定义日期。希望这会有所帮助


附加查询更新:添加这些导入

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

添加这一行代替等待

WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#divContainerIframeBmf > form > div > div > div:nth-child(1) > div:nth-child(3) > div > div > p')))

【讨论】:

非常感谢!如果问得不算多,您能否至少给我一个提示,告诉我如何更改此“time.sleep(50)”行?我想使用webdriver.wait,条件是网站的数据库查询完成,但我不知道它是如何做到的。有没有“jquery done”之类的? 添加这一行代替 sleep WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#divContainerIframeBmf > form > div > div > div:nth-child(1) > div:nth-child(3) > div > div > p'))) 从 selenium.webdriver.support.ui 导入 WebDriverWait 从 selenium.webdriver.support 导入预期条件作为 EC 从 selenium.webdriver.common.by导入方式

以上是关于在 python 中使用 selenium 从动态网站获取数据:如何发现数据库查询的完成方式?的主要内容,如果未能解决你的问题,请参考以下文章

使用 selenium 从动态网页表中查找值

如何在 Python 中使用 Selenium 设置动态显式等待?

在 Python 中使用 BS4、Selenium 抓取动态数据并避免重复

如何从动态网站python selenium中检索表

Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容

使用 Selenium 和 Python 进行用户输入的网页抓取动态网站