Webscraping - 试图提取一些数据,但陷入了最后的障碍
Posted
技术标签:
【中文标题】Webscraping - 试图提取一些数据,但陷入了最后的障碍【英文标题】:Webscraping - Trying to extract some data, but got stuck at the final hurdle 【发布时间】:2021-09-03 08:38:25 【问题描述】:我已经设法公开了正确的数据(其中一些是在页面中动态计算的,所以比我想象的要复杂一些)但是我现在需要在 JSON 字符串中获取它,尽管我做了很多尝试卡住了!
这个 Python 脚本如下(使用 Selenium 和 BeautifulSoup):
from bs4 import BeautifulSoup
from selenium import webdriver
import datetime
from dateutil import parser
import requests
import json
url = 'https://www.braintree.gov.uk/bins-waste-recycling/route-3-collection-dates/1'
browser = webdriver.Chrome(executable_path = r'C:/Users/user/Downloads/chromedriver.exe')
browser.get(url)
html = browser.execute_script("return document.getElementsByTagName('html')[0].innerHTML")
soup = BeautifulSoup(html, "html.parser")
data=soup.find_all("div", "class":"date_display")
#print(data)
#out =
for data in data:
bin_colour = data.find('h3').text
bin_date = parser.parse(data.find('p').text).strftime('%Y-%m-%d')
print(bin_colour)
print(bin_date)
print()
browser.quit()
这会导致:
Grey Bin
2021-06-30
Green Bin
2021-06-23
Clear Sack
2021-06-23
Food Bin
2021-06-23
它可能(可能)不是最好的代码/方法,所以我愿意接受您的建议。主要目标是:
"Grey Bin": "2021-06-30", "Green Bin": "2021-06-23", "Clear Sack": "2021-06-23", "Food Bin": "2021-06-23"
希望这是有道理的,我尝试了各种将数据转换为正确格式的方法,但似乎都丢失了,所以经过数小时的尝试后,我希望你们能提供帮助。
更新: MendelG 的两种解决方案都运行良好。 Vitalis 的解决方案提供了四个输出,最后一个是所需的输出 - 所以感谢你们提供非常快速和有效的解决方案 - 我很接近,但看不到树木的树木!
【问题讨论】:
【参考方案1】:要获取字典格式的数据,可以尝试:
out =
for data in tag:
out[data.find("h3").text] = parser.parse(data.find("p").text).strftime("%Y-%m-%d")
print(out)
或者,使用字典理解:
print(
data.find("h3").text: parser.parse(data.find("p").text).strftime("%Y-%m-%d")
for data in tag
)
输出:
'Grey Bin': '2021-06-30', 'Green Bin': '2021-06-23', 'Clear Sack': '2021-06-23', 'Food Bin': '2021-06-23'
【讨论】:
好吧,我以为我有解决方案,而且输出看起来确实正确,但是看起来正确和正确必须是不同的事情。输出的重点是让 Home Assistant 读取它。我正在使用 json.dumps(out) 所以我得到每条记录的双引号,但家庭助理没有识别任何东西,我得到一个空的回报。 @StuartHodgson 这是一个不同的问题。我建议将其发布为一个新问题【参考方案2】:您可以创建一个空字典,在其中添加值并打印它。
解决方案
from bs4 import BeautifulSoup
from selenium import webdriver
import datetime
from dateutil import parser
import requests
import json
url = 'https://www.braintree.gov.uk/bins-waste-recycling/route-3-collection-dates/1'
browser = webdriver.Chrome(executable_path='/snap/bin/chromium.chromedriver')
browser.get(url)
html = browser.execute_script("return document.getElementsByTagName('html')[0].innerHTML")
soup = BeautifulSoup(html, "html.parser")
data = soup.find_all("div", "class":"date_display")
result =
for item in data:
bin_colour = item.find('h3').text
bin_date = parser.parse(item.find('p').text).strftime('%Y-%m-%d')
result[bin_colour]=bin_date
print(result)
输出
'Grey Bin': '2021-06-30', 'Green Bin': '2021-06-23', 'Clear Sack': '2021-06-23', 'Food Bin': '2021-06-23'
如果你需要,你可以用类似的方式在list
中输出,但你需要.append
值,就像我在Trouble retrieving elements and looping pages using next page button 中所做的一样
如果您需要双引号,请使用此打印:
print(json.dumps(result))
它将打印:
"Grey Bin": "2021-06-30", "Green Bin": "2021-06-23", "Clear Sack": "2021-06-23", "Food Bin": "2021-06-23"
【讨论】:
【参考方案3】:您可以使用requests
和re
收集所有列出的日期。您正则表达式输出包含每个集合类型的日期的各种 javascript 对象。然后,您需要在每个月的值上加 1,以获得 1-12 范围内的月份;这可以通过正则表达式命名组来完成。这些可以转换为实际日期以供以后过滤。
最初将所有日期存储在字典中,其中键作为集合类型,值作为集合日期列表,您可以使用zip_longest
创建DataFrame
。然后,您可以使用过滤来查找给定集合的下一个集合日期。
我使用了几个辅助函数来实现这一点。
import requests
from dateutil import parser
from datetime import datetime
from pandas import to_datetime, DataFrame
from itertools import zip_longest
def get_dates(dates):
dates = [re.sub(r'(?P<g1>\d+),(?P<g2>\d+),(?P<g3>\d+)$', lambda d: parser.parse('-'.join([d.group('g1'), str(int(d.group('g2')) + 1), d.group('g3')])).strftime('%Y-%m-%d'), i)
for i in re.findall(r'Date\((\d4,\d1,2,\d1,2),', dates)]
dates = [datetime.strptime(i, '%Y-%m-%d').date() for i in dates]
return dates
def get_next_collection(collection, df):
return df[df[collection] >= to_datetime('today')][collection].iloc[0]
collection_types = ['grey', 'green', 'clear', 'food']
r = requests.get('https://www.braintree.gov.uk/bins-waste-recycling/route-3-collection-dates/1')
collections =
for collection in collection_types:
dates = re.search(r'var 0(?:(?:bin)|(?:sack)) = (\[.*?\])'.format(collection), r.text, re.S).group(1)
collections[collection] = get_dates(dates)
df = DataFrame(zip_longest(collections['grey'], collections['green'],
collections['clear'], collections['food']),
columns = collection_types)
get_next_collection('grey', df)
您还可以使用生成器和islice
,如@Martijn Pieters
所述,直接处理字典条目(保存收集日期)并限制您感兴趣的未来日期的数量,例如
filtered = (i for i in collections['grey'] if i >= date.today())
list(islice(filtered, 3))
更改的导入行是:
from itertools import zip_longest, islice
from datetime import datetime, date
然后,您不需要 pandas
导入或创建 DataFrame
。
【讨论】:
以上是关于Webscraping - 试图提取一些数据,但陷入了最后的障碍的主要内容,如果未能解决你的问题,请参考以下文章
Chatgpt-3 使用的提取积累数据集技术和数据集自动化处理