I just tried you’re specific location with the select value as mentioned and it’s resulting in a value without any issues or errors. For the comparison, I’m running Homeassistant 73.1 with Docker.
Finally, it’s working.
Somehow I ended up with faulty quotes in my config…
- platform: scrape
resource: https://www.shellexpress.nl/nl_nl/station/se-nieuwerkerk-aan-den-ijssel
name: Shell Express
select: ".price-actual"
value_template: '{{ value.split(" ")[0] }}'
scan_interval: 3600
- platform: scrape
name: Tinq
resource: "http://www.tinq.nl/tankstation?id=251"
select: "#station-prijzen tr:nth-of-type(3) td:nth-of-type(2)"
value_template: "{{ value.split('\xa0')[1].replace(' ','').replace(',', '.') | float }}"
scan_interval: 3600
- platform: scrape
resource: "http://lukoil.nl/go/lukoil_station.cfm?id=465"
name: Lukoil
select: "#tabbedInfoContent div:nth-of-type(14)"
value_template: "{{ value.split('\x0D')[2].replace('EUR/L', '').replace(',', '.') | float }}"
scan_interval: 3600
- platform: scrape
resource: "https://www.tango.nl/stations/tango-nieuwerkerk-ad-ijssel"
name: Tango
select: “#euro95 .pump_price span.price” #<<<<<<<<<< FAULTY QUOTES
scan_interval: 3600
If you look closely to the original example, that’s were they came from.
Using this for the last 3 months gave me some nice stats in Grafana, cleary showing how long they wait to drop the prices at Shell Express and how fast they raise the price.
# Benzine Prijzen
- platform: scrape
name: Euro95
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: ".table div:nth-of-type(8)"
value_template: "{{ value.split(' ')[1].replace(',', '.') | float }}"
scan_interval: 3600 # be nice; once per hour only
- platform: scrape
resource: "https://shellexpress.nl/nl_nl/station/se-santpoort"
name: Shell_Express_Santpoort
select: ".price-actual"
value_template: "{{ value.split(' ')[0].replace(',', '.') | float }}"
scan_interval: 3600
But United Consumers seem to have done something in their website code resulting in a 0.0 price.
I have tried to make cheese how this scrape works with the inspect option from Google Chrome but no luck.
Also Shell has changed the website for the individual tankstations. The url (“https://shellexpress.nl/nl_nl/station/se-pijnacker” in my case) now goes to a general page where you have to select a station. I haven’t found a fix for it yet sadly enough.
Not sure if its the website, I did read there was some fix in the scraper because of a bug the code for UnitedConsumer was working.
FYI i’m having the same issue resulting in a 0.0 price. Not sure how to fix as i have no experience with select part
I still hope someone can make it work from the Directlease website?
Or other also good.
Looking for Esso Express and Texaco.
Tinq already work now
They changed a few things so I’ve updated your config and expanded it a little bit. I’m by no means a pro, just a noob trying stuff by trail and error.
You’ll need this, to make this work: https://github.com/kalkih/mini-graph-card
configuration 26/02/2019
customize.yaml
sensor.diesel_value:
friendly_name: "Diesel"
icon: mdi:gas-station
sensor.euro95_value:
friendly_name: "Euro 95"
icon: mdi:gas-station
sensor.lpg_value:
friendly_name: "LPG"
icon: mdi:gas-station
configuration.yaml
sensor:
# SCRAPING GAS PRICES
- platform: scrape
name: Euro95
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: "div.row:nth-of-type(2) div.col-xs-4:nth-of-type(3)"
scan_interval: 3600
- platform: scrape
name: Diesel
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: "div.row:nth-of-type(3) div.col-xs-4:nth-of-type(3)"
scan_interval: 3600
- platform: scrape
name: LPG
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: "div.row:nth-of-type(4) div.col-xs-4:nth-of-type(3)"
scan_interval: 3600
# TEMPLATING GAS PRICES
- platform: template
sensors:
euro95_value:
friendly_name: "Euro 95"
unit_of_measurement: "€/l"
value_template: "{{ states('sensor.euro95') |replace('€', '') |replace(',', '.') |round(3) }}"
diesel_value:
friendly_name: "Diesel"
unit_of_measurement: "€/l"
value_template: "{{ states('sensor.diesel') |replace('€', '') |replace(',', '.') |round(3) }}"
lpg_value:
friendly_name: "LPG"
unit_of_measurement: "€/l"
value_template: "{{ states('sensor.lpg') |replace('€', '') |replace(',', '.') |round(3) }}"
ui-lovelace.yaml
- type: vertical-stack
cards:
- type: markdown
content: >
## <center>BRANDSTOF PRIJZEN</center>
- type: entities
entities:
- sensor.euro95_value
- sensor.diesel_value
- sensor.lpg_value
- type: horizontal-stack
cards:
- type: custom:mini-graph-card
entities:
- entity: sensor.euro95_value
name: Euro 95
hour24: true
font_size: 75
decimals: 3
show:
graph: bar
points_per_hour: 0.25
hours_to_show: 168
line_color: '#7FFF00'
- type: custom:mini-graph-card
entities:
- entity: sensor.diesel_value
name: Diesel
hour24: true
font_size: 75
decimals: 3
show:
graph: bar
points_per_hour: 0.25
hours_to_show: 168
line_color: '#FF0000'
- type: custom:mini-graph-card
entities:
- entity: sensor.lpg_value
name: LPG
hour24: true
font_size: 75
decimals: 3
show:
graph: bar
points_per_hour: 0.25
hours_to_show: 168
line_color: '#FFF68F'
I just dropped into this thread and made some adjustments.
Check my post.
YES!!! Got the “adviesprijs” back. Thank you so much!
Probably a change in the scraper. The 8th div was literal earlier, but now it is in the hierarchy. This is my adjusted config
sensor:
- platform: scrape
name: Euro95 Advies
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: ".table div:nth-of-type(2) div:nth-of-type(3)"
value_template: "{{ value |replace('€', '') |replace(',', '.') |round(3) }}"
scan_interval: 3600 # be nice; once per hour only
- platform: scrape
name: Diesel Advies
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: ".table div:nth-of-type(3) div:nth-of-type(3)"
value_template: "{{ value |replace('€', '') |replace(',', '.') |round(3) }}"
scan_interval: 3600 # be nice; once per hour only
- platform: scrape
name: LPG Advies
resource: "https://www.unitedconsumers.com/brandstofprijzen"
select: ".table div:nth-of-type(4) div:nth-of-type(3)"
value_template: "{{ value |replace('€', '') |replace(',', '.') |round(3) }}"
scan_interval: 3600 # be nice; once per hour only
Thanks that did the trick
My solution to the prices was a python3 script:
from bs4 import BeautifulSoup
import requests
import json
###Take the url name from "https://www.brandstof-zoeker.nl/"
###Example: "https://www.brandstof-zoeker.nl/station/avia-h-i-ambacht-hendrik-ido-ambacht-771/"
###Mutiple stations supported (comma seprated)
stationList = ['avia-h-i-ambacht-hendrik-ido-ambacht-771']
list = {}
for station in stationList:
stationName = station.split('-',1)[0]
###load website with request
result = requests.get("https://www.brandstof-zoeker.nl/station/{0}/".format(station))
###Get content from request website
content = result.content
###Load content in bs4
soup = BeautifulSoup(content, "html.parser")
###Put body in variable
soupBody = soup.body
###try if available, catches errors
try:
diesel = soupBody.find_all('dd')[0]
except IndexError:
diesel = 'null'
###try if available, catches errors
try:
euro95 = soupBody.find_all('dd')[1]
except IndexError:
euro95 = 'null'
###If error change both values to not available, prevents euro95 and diesel pricing mixup
if euro95 == 'null' or diesel == 'null':
dieselClean = "Not available"
euro95Clean = "Not available"
else:
###Gets pricing line from beautifull soup input
diesel = soupBody.find_all('dd')[0]
euro95 = soupBody.find_all('dd')[1]
###Strips everything except price
euro95Clean = str(euro95).split('\n',1)[-1].split('\n', 1)[0].split(' ', 1)[-1].split(' ', 1)[0]
dieselClean = str(diesel).split('\n',1)[-1].split('\n', 1)[0].split(' ', 1)[-1].split(' ', 1)[0]
###creates a list in json format so homeassistant templates can be used.
list["{0}".format(stationName)] = {"euro95": "{0}".format(euro95Clean),"diesel": "{0}".format(dieselClean)}
encapsulatedList = {"list": list}
json = json.dumps(encapsulatedList)
print(json)
This script outputs a JSON array with the prices. Next I added a sensor in hass to get the output as a sensor.
- platform: command_line
name: 'gasPrice'
command: "python /config/scripts/gasprice/gasPrices.py"
scan_interval: 60
json_attributes: ['list']
To avoid multiple request to the site for every gasstation I created a template to extract the data from the commandline sensor to sepperate entities. This I did with the following sensors:
- platform: template
sensors:
shell_euro95:
unit_of_measurement: '€'
value_template: >-
{{- state_attr('sensor.gasPrice', 'list').shell.euro95 -}}
berkman_euro95:
unit_of_measurement: '€'
value_template: >-
{{- state_attr('sensor.gasPrice', 'list').berkman.euro95 -}}
Works perfect! Too bad the Tamoil close by doesn’t give any information via www.brandstof-zoeker.nl.
But even for a n00b like me, I got it working. Thanks!
Tinq has recenlty done an update on their site, so the example in this topic doesn’t work anymore.
I am now playing with BeautifulSoup to get the diesel price from my local fueling station, but I have too little experience to get there. Is there anyone able to help?
What I have so far is:
import requests
from bs4 import BeautifulSoup
page = requests.get("https://www.tinq.nl/tankstations/nootdorp-kerkweg")
soup = BeautifulSoup(page.content, 'html.parser')
soupBody = soup.body
diesel = soupBody.select("div.field.field--name-field-station-prices.field--type-entity-reference.field--label-above > div.field__items > div:nth-child(1) > div > div.field.field--name-field-prices-price-pump.field--type-float.field--label-hidden.field__item")
print(diesel)
this is the output:
[<div class="field field--name-field-prices-price-pump field--type-float field--label-hidden field__item" content="1.349">€ 1.34<sup>9</sup><span>EUR/L</span></div>]
And that’s where I’m stuck at the moment. I see the correct price in the content tag, so that would be the easiest place in my opinion to get the price from, but how do I get it from there?
edit: sometimes it helps to ask for help to get to the sollution yourself
looking at the example from @legoracers I found the following sollution:
dieselstripped = str(diesel).split('=',2)[-1].split('>',1)[0].split('"')[1]
print(dieselstripped)
or (even shorter)
dieselstripped = str(diesel).split('"')[3]
Maybe not the best sollution, but it works for now!
You can have a look at the fuel package in my configuration repo for Tinq using the scrape sensor.
BTW, Lukoil also changed their website recently. I fixed that as well.
Hero! I just noticed my Tinq sensors were broken for a long time and finally decided to check their website. That has changed quite a bit
Your code works excellent. Direct link for others (as it includes more brands): https://github.com/metbril/home-assistant-config/blob/00d68bae7c6ec525ea28c712773645acd42b9a7d/packages/fuel.yaml
As i needed quite a few vendors I decided to go another way and build an OCR api on top of directlease.nl. You can try it here:
https://brandstof-api.sanwil.net/docs#/default/api_brandstof_prijs_api_v1_brandstof_prijzen__png__get
Just paste in a png filename such as “7025.png” (i didn’t see the numbers switching over time).
Direct endpoint would be “https://brandstof-api.sanwil.net/api/v1/brandstof_prijzen/7025.png” for example.
Let me know what you think. Later on i can make it run faster (it’s on a slow server now). For now it supplies the gasoline and diesel prices. ocr_station is just an indication of the first OCR line in the image, so don’t use it.
Whoa, you’re taking this to a whole different level this way!
I just need the diesel and benzine prices of 2 different TinQ stations, so the scrape is fine for me now.
I was just playing with the scrape function but I was not able to get the data from the esso and shell sites so I will look to your solution. I’ll tried a few and it seems to work fine, not slow at all. As a copy-paste programmer I have to look how to get the data into HA.