更新for循环中的列表和词典时出现问题

时间:2018-03-01 04:25:01

标签: python selenium for-loop beautifulsoup html-parsing

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import bs4
import datetime
import time

#options = Options()
#options.add_argument("--headless")
#driver = webdriver.Firefox(firefox_options=options)

driver = webdriver.Firefox()

driver.get("https://www.rankonesport.com/Calendar/?D=e8bb5c10-8d0c-4b26-
b304-262397124de8")

weekly = driver.find_element_by_id("cmd_Weekly").click()

source = driver.page_source

bs_source = bs4.BeautifulSoup(source, "lxml")

month = datetime.date.today().month

year_end = 5
total = 12
times = 0

if month <= year_end:
    times = year_end - month

if month == year_end:
    times = 1

if month >= year_end:
    value = month - year_end

    times = total - value

times *= 5

mylist = []
#{EventName:[Date, Where, Time(Start), Time(End)]}
mydict = {}

for x in range(times):


    events = bs_source.find('table', id='gv_Events')


    for tr in events.find_all('tr', class_='lightgray'):

        td = tr.find_all('td')
        mylist.append(td)

    for tr2 in events.find_all('tr', class_='white'):

        td2 = tr2.find_all('td')
        mylist.append(td2)

    next = driver.find_element_by_id('lnk_Next_Day').click()


for event in mylist:
    mydict.update({event[0].text: [event[2].text, event[1].text, 
    event[3].text, event[4].text]})

print(mylist)
print(mydict)

所以我的学校有一个在线日历,我正试图撇开。我的目标是拉出学校年结束前发生的每个事件,以及相应的属性,如时间和日期。

我让脚本循环遍历具有每周事件的日历部分并将其拉出。日历是基于JS的日历,因此当脚本转到并单击下一个按钮时,链接不会更改。我将事件及其属性存储在列表中,然后将它们放入字典中,以便通过名称轻松访问它们。

我想要发生的是字典中充满了与脚本循环一样多的事件。相反,字典只包含少数几个似乎是它解析的第一对事件。当下一页被拉起时,事件具有相同的HTML ID和类,因此它应该像我一样多次冲洗和重复代码。

如果有人可以指出一些我错过的东西,或者引导我朝着正确的方向前进,这将是非常棒的,因为我花了很多时间试图弄明白这一点。

链接:

Calendar
Calendar Outline

字典输出:

{'Sadie Ticket Sales': ['3/1/2018', 'New Cafeteria, 541 Chartres St. LaSalle, Lasalle, IL 61301', '11:00 AM', '1:00 PM'], 
 'Winter Guard Practice': ['3/3/2018', ' East Gym, 541 Chartres St. LaSalle, Lasalle, IL 61301', '5:00 PM', '8:00 PM'], 
 'Sadie Dance': ['3/3/2018', 'Sellett Gym, 541 Chartres St. LaSalle, Lasalle, IL 61301', '8:00 PM', '11:00 PM']}

^应该是方式,更多事件

列出输出:

[[<td>Sadie Ticket Sales</td>, <td>New Cafeteria, 541 Chartres St. LaSalle, Lasalle, IL 61301</td>, <td>2/26/2018</td>, <td>11:00 AM</td>, <td>1:00 PM</td>, <td>Non-Game Activity</td>, <td align="center"><a href="javascript:__doPostBack('gv_Events','Outlook$0')">Sync</a></td>],
 [<td>Winter Guard Practice</td>, <td>North Balcony, 541 Chartres St. LaSalle, Lasalle, IL 61301</td>, <td>2/27/2018</td>, <td>6:30 PM</td>, <td>9:00 PM</td>, <td>Non-Game Activity</td>, <td align="center"><a href="javascript:__doPostBack('gv_Events','Outlook$2')">Sync</a></td>],
 ...]

似乎在列表中一遍又一遍地重复这些事件^

感谢。

编辑1:

mylist = []
#{EventName:[Date, Where, Time(Start), Time(End)]}
mydict = {}

for x in range(5):

    source = driver.page_source

    bs_source = bs4.BeautifulSoup(source, 'lxml')
    events = bs_source.find('table', id='gv_Events')


    for tr in events.find_all('tr', class_='lightgray'):

        td = tr.find_all('td')
        mylist.append(td)

    for tr2 in events.find_all('tr', class_='white'):

        td2 = tr2.find_all('td')
        mylist.append(td2)

    next = driver.find_element_by_id('lnk_Next_Day').click()


for event in mylist:
    mydict.update({event[0].text: [event[2].text, event[1].text, 
    event[3].text, event[4].text]})

2 个答案:

答案 0 :(得分:1)

不是解析html,而是下载excel文件呢?这似乎下载了你所追求的所有事件。

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

url = "https://www.rankonesport.com/Calendar/?D=e8bb5c10-8d0c-4b26-b304-262397124de8"

driver = webdriver.Chrome()
driver.get(url)

weekly = driver.find_element_by_id("cmd_Weekly")
weekly.click()

while True:
    try:
        element = WebDriverWait(driver, 5).until(
            EC.presence_of_element_located((By.ID, "cmd_Export_Event_Excel"))
        ).click()
    except TimeoutException:
        driver.quit()
        break
    else:
        driver.find_element_by_id('lnk_Next_Day').click()

然后,使用pandas和stackoverflow的一些帮助,您可以将结果写入csv文件。

import os
from functools import reduce

import pandas as pd

dfs = []
dir_path = '/home/lettuce/Downloads'
for f in os.listdir(dir_path):
    if f.endswith('.xls'):
        df = pd.read_html('{}/{}'.format(dir_path, f))[0]
        dfs.append(df)

df_final = reduce(lambda left, right: pd.merge(left, right, how='outer'), dfs)
df_final.to_csv('all_events.csv', index=False, header=False)

Link to the csv output file

答案 1 :(得分:0)

您只需在脚本开头提取一次页面内容:

source = driver.page_source

bs_source = bs4.BeautifulSoup(source, "lxml")

当您点击“下一步”浏览日历时,bs_source将继续包含第一页的来源,这意味着您将永远重新处理第一页。

最简单的解决方法是在循环开始时实例化bs_source,然后再查找任何元素。