-
-
Save Surendrajat/ff3876fd2166dd86fb71180f4e9342d7 to your computer and use it in GitHub Desktop.
"custom/weather": { | |
"exec": "python ~/.config/waybar/scripts/weather.py", | |
"restart-interval": 300, | |
"return-type": "json", | |
"on-click": "xdg-open https://weather.com/en-IN/weather/today/l/$(location_id)" | |
// "format-alt": "{alt}", | |
}, |
#custom-weather.severe { | |
color: #eb937d; | |
} | |
#custom-weather.sunnyDay { | |
color: #c2ca76; | |
} | |
#custom-weather.clearNight { | |
color: #2b2b2a; | |
} | |
#custom-weather.cloudyFoggyDay, #custom-weather.cloudyFoggyNight { | |
color: #c2ddda; | |
} | |
#custom-weather.rainyDay, #custom-weather.rainyNight { | |
color: #5aaca5; | |
} | |
#custom-weather.showyIcyDay, #custom-weather.snowyIcyNight { | |
color: #d6e7e5; | |
} | |
#custom-weather.default { | |
color: #dbd9d8; | |
} |
#!/usr/bin/env python | |
import subprocess | |
from pyquery import PyQuery # install using `pip install pyquery` | |
import json | |
# weather icons | |
weather_icons = { | |
"sunnyDay": "滛", | |
"clearNight": "望", | |
"cloudyFoggyDay": "", | |
"cloudyFoggyNight": "", | |
"rainyDay": "", | |
"rainyNight": "", | |
"snowyIcyDay": "", | |
"snowyIcyNight": "", | |
"severe": "", | |
"default": "", | |
} | |
# get location_id | |
# to get your own location_id, go to https://weather.com & search your location. | |
# once you choose your location, you can see the location_id in the URL(64 chars long hex string) | |
# like this: https://weather.com/en-IN/weather/today/l/c3e96d6cc4965fc54f88296b54449571c4107c73b9638c16aafc83575b4ddf2e | |
location_id = "c3e96d6cc4965fc54f88296b54449571c4107c73b9638c16aafc83575b4ddf2e" # TODO | |
# location_id = "8139363e05edb302e2d8be35101e400084eadcecdfce5507e77d832ac0fa57ae" | |
# priv_env_cmd = 'cat $PRIV_ENV_FILE | grep weather_location | cut -d "=" -f 2' | |
# location_id = subprocess.run( | |
# priv_env_cmd, shell=True, capture_output=True).stdout.decode('utf8').strip() | |
# get html page | |
url = "https://weather.com/en-IN/weather/today/l/" + location_id | |
html_data = PyQuery(url=url) | |
# current temperature | |
temp = html_data("span[data-testid='TemperatureValue']").eq(0).text() | |
# print(temp) | |
# current status phrase | |
status = html_data("div[data-testid='wxPhrase']").text() | |
status = f"{status[:16]}.." if len(status) > 17 else status | |
# print(status) | |
# status code | |
status_code = html_data("#regionHeader").attr("class").split(" ")[2].split("-")[2] | |
# print(status_code) | |
# status icon | |
icon = ( | |
weather_icons[status_code] | |
if status_code in weather_icons | |
else weather_icons["default"] | |
) | |
# print(icon) | |
# temperature feels like | |
temp_feel = html_data( | |
"div[data-testid='FeelsLikeSection'] > span > span[data-testid='TemperatureValue']" | |
).text() | |
temp_feel_text = f"Feels like {temp_feel}c" | |
# print(temp_feel_text) | |
# min-max temperature | |
temp_min = ( | |
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']") | |
.eq(0) | |
.text() | |
) | |
temp_max = ( | |
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']") | |
.eq(1) | |
.text() | |
) | |
temp_min_max = f" {temp_min}\t\t {temp_max}" | |
# print(temp_min_max) | |
# wind speed | |
wind_speed = html_data("span[data-testid='Wind']").text().split("\n")[1] | |
wind_text = f"煮 {wind_speed}" | |
# print(wind_text) | |
# humidity | |
humidity = html_data("span[data-testid='PercentageValue']").text() | |
humidity_text = f" {humidity}" | |
# print(humidity_text) | |
# visibility | |
visbility = html_data("span[data-testid='VisibilityValue']").text() | |
visbility_text = f" {visbility}" | |
# print(visbility_text) | |
# air quality index | |
air_quality_index = html_data("text[data-testid='DonutChartValue']").text() | |
# print(air_quality_index) | |
# hourly rain prediction | |
prediction = html_data("section[aria-label='Hourly Forecast']")( | |
"div[data-testid='SegmentPrecipPercentage'] > span" | |
).text() | |
prediction = prediction.replace("Chance of Rain", "") | |
prediction = f"\n\n (hourly) {prediction}" if len(prediction) > 0 else prediction | |
# print(prediction) | |
# tooltip text | |
tooltip_text = str.format( | |
"\t\t{}\t\t\n{}\n{}\n{}\n\n{}\n{}\n{}{}", | |
f'<span size="xx-large">{temp}</span>', | |
f"<big>{icon}</big>", | |
f"<big>{status}</big>", | |
f"<small>{temp_feel_text}</small>", | |
f"<big>{temp_min_max}</big>", | |
f"{wind_text}\t{humidity_text}", | |
f"{visbility_text}\tAQI {air_quality_index}", | |
f"<i>{prediction}</i>", | |
) | |
# print waybar module data | |
out_data = { | |
"text": f"{icon} {temp}", | |
"alt": status, | |
"tooltip": tooltip_text, | |
"class": status_code, | |
} | |
print(json.dumps(out_data)) |
Surendrajat
commented
Oct 19, 2021
Could you pointed out where localtion_id
in this line is defined? In my env it is not expanded and the resulting URL is https://weather.com/en-IN/weather/today/l/
.
Could you pointed out where localtion_id in this line is defined? In my env it is not expanded and the resulting URL is https://weather.com/en-IN/weather/today/l/.
https://gist.github.com/Surendrajat/ff3876fd2166dd86fb71180f4e9342d7#file-weather-py-L21=
I already set my location from there (in weather.py
), but the hash value is not available in ~/.config/waybar/config
. Does it work for you?
Yeah that won't work unless you replace it with actual location_id
or export a shell variable location_id
as I do.
I noticed today that something may have changed in the https://weather.com/en-IN/weather/today/l/...
webpage and the html_data
filters may now be broken.
I initially realized it because of the following error:
[2022-10-28 10:40:55.065] [error] weather stopped unexpectedly, is it endless?
Traceback (most recent call last):
File "/home/crazybyte/.config/waybar/modules/weather", line 92, in <module>
wind_speed = html_data(
IndexError: list index out of range
The CSS item is now class .Wind--windWrapper--3Ly7c
instead of .Wind--windWrapper--3aqXJ
, but fixing it is not enough to make the script works properly again.
May I ask you why are you scraping data from the web-page instead of querying some API endpoints?
@StayPirate Thanks for letting me know. I'm not using sway right now, but I've tried to update the script for now and hopefully made it less fragile. (Probably you can fork and maintain it if you're interested)
May I ask you why are you scraping data from the web-page instead of querying some API endpoints?
Yeah that'd be simpler, but I actively try to avoid signing up for services that are otherwise accessible.
I get his error when i try to run, i've changed it my own location
Traceback (most recent call last):
File "/home/shabirk/.config/waybar/modules/weather.py", line 46, in
status_code = html_data("#regionHeader").attr("class").split(" ")[2].split("-")[2]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'split'
Traceback (most recent call last):
File "/home/shabirk/.config/waybar/modules/weather.py", line 46, in
status_code = html_data("#regionHeader").attr("class").split(" ")[2].split("-")[2]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'split'
The new document of pyquery module shows the method below will no longer fetch the contents of the URL.
url = "https://weather.com/en-IN/weather/today/l/" + location_id
html_data = PyQuery(url)
The right way
url_fetch = "https://weather.com/en-IN/weather/today/l/" + location_id
html_data = PyQuery(url=url_fetch)
Thanks @k1tyoo for tracking it down. I've updated the script to work with pyquery
1 & 2 now.
What are the default icons, as a lot of them are not showing for me, other than that I appreciate the work you have done and it's a great module :)
@CerealKiller-John thanks. I've mostly used font-awesome icons and few icons from nerd-fonts. This is my setup:
@CerealKiller-John thanks. I've mostly used font-awesome icons and few icons from nerd-fonts. This is my setup:
Thank you, I also was wondering is there a way to incorporate current location into this? As I am using it on a laptop, I wouldn't really need to know my home forecast if I am not at home. I know I could update the key, but I was wondering if there was an easier way?
I also was wondering is there a way to incorporate current location into this?
I guess you can get your lat-long from laptop's GPS and submit it to weather.com's HTML form (using a similar script) and get location id from redirection URL. It'll a bit complicated and will depend on the accuracy of your GPS. Anyway, you might be better off with some API from weather providers at that point.
Hello there! Thanks for this wonderful module. In the past few days, I've realized that the "Feels like" section inside the tooltip does not print out any value. I'm not sure why, as the values seem to align with the website its scrapes from. Any ideas about how to fix?
Looks like they've added one more <span>
wrapper around the temp value. Anyway I've fixed it for now. Cheers.
Is it possible to get Fahrenheit? I notice there is no separate URL for Fahrenheit on the website, guess some JS handling or something.
Possible to get 5-day?
When I click the popup/dropdown thing, goes to 404 page: https://weather.com/en-IN/weather/today/l/
ie. missing location_id at that point.
Hi, it seems they must have changed the min/max temp, because it's now reversed.
By changing :
# min-max temperature
temp_min = (
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']")
.eq(0)
.text()
)
temp_max = (
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']")
.eq(1)
.text()
)
To
# min-max temperature
temp_min = (
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']")
.eq(1) # <- Changed here
.text()
)
temp_max = (
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']")
.eq(0) # <- Changed here
.text()
)
You get the right values again.
Here are some screenshot to display what I'm talking about :
If this is a problem on my side, I apologize for the disturbance !