Использование selenium в python для получения данных с динамического веб-сайта: как узнать, как выполняются запросы к базам данных? - PullRequest
0 голосов
/ 13 сентября 2018

Раньше у меня был некоторый опыт программирования, но не специально для веб-приложений. Мне было поручено получить данные с этого сайта: 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, и пока результаты хорошие: я могу получить всю таблицу, сохранить ее в фрейме данных 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]

Таблица, полученная из этой функции, всегда одна и та же, независимо от того, какие входные данные я ей отправляю. И они, кажется, с соответствующей датой 09/09/2018 (месяц = ​​09, день = 06). Я думаю, что основная проблема заключается в том, что я не знаю, как выполняются запросы к их базе данных, поэтому это всегда выполняется как «дата по умолчанию». Я читал некоторых людей, говорящих о запросах Ajax и JavaScript, но я не знаю, так ли это. Как я могу сказать?

1 Ответ

0 голосов
/ 13 сентября 2018

Этот код будет работать (обновлено несколько строк в вашем коде)

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')))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...