Commit 8db14cf0 authored by Bezleputh's avatar Bezleputh Committed by Vincent A

[meteofrance] fix #383

parent db305d71
Pipeline #3336 passed with stages
in 13 minutes and 31 seconds
......@@ -18,21 +18,46 @@
# along with this weboob module. If not, see <http://www.gnu.org/licenses/>.
from weboob.browser import PagesBrowser, URL
from .pages import WeatherPage, SearchCitiesPage
from .pages import WeatherPage, SearchCitiesPage, HomePage
__all__ = ['MeteofranceBrowser']
class MeteofranceBrowser(PagesBrowser):
BASEURL = 'http://www.meteofrance.com'
cities = URL('mf3-rpc-portlet/rest/lieu/facet/previsions/search/(?P<pattern>.*)', SearchCitiesPage)
weather = URL('previsions-meteo-france/(?P<city_name>.*)/(?P<city_id>.*)', WeatherPage)
BASEURL = 'https://meteofrance.com'
cities = URL(r'/search/all\?term=(?P<pattern>.*)',
SearchCitiesPage)
weather = URL(r'https://rpcache-aa.meteofrance.com/internet2018client/2.0/forecast\?lat=(?P<lat>.*)&lon=(?P<lng>.*)&id=&instants=&day=2',
WeatherPage)
home = URL('', HomePage)
def _fill_header(self):
self.home.go()
mfessions = self.session.cookies.get('mfsession')
token = ''
for c in mfessions:
if c.isalpha():
t = 97 if c.islower() else 65
token += chr(t + (ord(c) - t + 13) % 26)
else:
token += c
self.session.headers['Authorization'] = 'Bearer %s' % token
self.session.headers['Sec-Fetch-Site'] = 'same-site'
self.session.headers['Sec-Fetch-Mode'] = 'cors'
def iter_city_search(self, pattern):
return self.cities.go(pattern=pattern).iter_cities()
def iter_forecast(self, city):
return self.weather.go(city_id=city.id, city_name=city.name).iter_forecast()
if not self.session.headers.get('Authorization', None):
self._fill_header()
return self.weather.go(lng=city._lng, lat=city._lat).iter_forecast()
def get_current(self, city):
return self.weather.go(city_id=city.id, city_name=city.name).get_current()
if not self.session.headers.get('Authorization', None):
self._fill_header()
return self.weather.go(lng=city._lng, lat=city._lat).get_current()
......@@ -18,20 +18,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see <http://www.gnu.org/licenses/>.
from datetime import date
from datetime import date, datetime
from weboob.browser.pages import JsonPage, HTMLPage
from weboob.browser.elements import ItemElement, ListElement, DictElement, method
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.weather import Forecast, Current, City, Temperature
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.capabilities.weather import Forecast, Current, City, Temperature, Precipitation, Direction
from weboob.browser.filters.json import Dict
from weboob.browser.filters.standard import CleanText, CleanDecimal, Regexp, Format, Eval
from weboob.browser.filters.standard import CleanText, Format, Field
class SearchCitiesPage(JsonPage):
@method
class iter_cities(DictElement):
ignore_duplicate = True
# ignore_duplicate = True
class item(ItemElement):
klass = City
......@@ -39,68 +38,89 @@ class SearchCitiesPage(JsonPage):
def condition(self):
return Dict('type')(self) == "VILLE_FRANCE"
obj_id = Dict('codePostal')
obj_name = Dict('slug')
obj_id = Dict('cp')
obj_name = Dict('name')
obj__lng = Dict('lng')
obj__lat = Dict('lat')
class WeatherPage(HTMLPage):
class HomePage(HTMLPage):
pass
class WeatherPage(JsonPage):
@method
class iter_forecast(ListElement):
item_xpath = '//div[@class="liste-jours"]/ul/li'
class get_current(ItemElement):
klass = Current
class item(ItemElement):
klass = Forecast
def parse(self, el):
now = datetime.now()
self.cpt = 0
for item in Dict('properties/forecast')(el):
if datetime.strptime(item['time'], '%Y-%m-%dT%H:%M:%S.%fZ') < now:
self.cpt = self.cpt + 1
else:
break
obj_date = date.today()
obj_id = CleanText('./dl/dt')
def obj_date(self):
actual_day_number = Eval(int,
Regexp(CleanText('./dl/dt'),
'\w{3} (\d+)'))(self)
base_date = date.today()
if base_date.day > actual_day_number:
base_date = base_date.replace(
month=(
(base_date.month % 12) + 1
)
)
base_date = base_date.replace(day=actual_day_number)
return base_date
def obj_id(self):
return Dict('properties/forecast/{}/time'.format(self.cpt))(self)
def obj_low(self):
temp = Regexp(CleanText('./dl/dd/span[@class="min-temp"]'),
u'(\d*)\xb0\w Minimale.*')
if temp != "-": # Sometimes website does not return low
temp = CleanDecimal(temp)(self)
unit = Regexp(CleanText('./dl/dd/span[@class="min-temp"]'), u'.*\xb0(\w) Minimale.*')(self)
return Temperature(float(temp), unit)
return NotAvailable
def obj_text(self):
return Format(u'%s - %s probability %s%% - Cloud coverage %s%% - Wind %s km/h %%s - Humidity %s%% - Pressure %s hPa',
Dict('properties/forecast/{}/weather_description'.format(self.cpt)),
Field('precipitation'),
Field('precipitation_probability'),
Field('wind_speed'),
Dict('properties/forecast/{}/total_cloud_cover'.format(self.cpt)),
Dict('properties/forecast/{}/wind_direction'.format(self.cpt)),
Field('wind_direction'),
Field('humidity'),
Field('pressure'))(self)
def obj_high(self):
temp = Regexp(CleanText('./dl/dd/span[@class="max-temp"]'),
u'(.*)\xb0\w Maximale.*')(self)
if temp != "-": # Sometimes website does not return high
temp = CleanDecimal(temp)(self)
unit = Regexp(CleanText('./dl/dd/span[@class="max-temp"]'), u'.*\xb0(\w) Maximale.*')(self)
return Temperature(float(temp), unit)
return NotAvailable
def obj_precipitation_probability(self):
return float(Dict('properties/forecast/{}/rain_1h'.format(self.cpt), default=0)(self))
obj_text = CleanText('./@title')
def obj_precipitation(self):
return Precipitation.RA
@method
class get_current(ItemElement):
klass = Current
def obj_wind_direction(self):
return Direction[CleanText(Dict('properties/forecast/{}/wind_icon'.format(self.cpt)),
replace=[('O', 'W')])(self)]
obj_id = date.today()
obj_date = date.today()
obj_text = Format('%s - %s - %s - Vent %s',
CleanText('//ul[@class="prevision-horaire "]/li[@class=" active "]/div/ul/li[@class="day-summary-tress-start"]'),
CleanText('//ul[@class="prevision-horaire "]/li[@class=" active "]/div/ul/li[@class="day-summary-image"]'),
CleanText('//ul[@class="prevision-horaire "]/li[@class=" active "]/div/ul/li[@class="day-summary-uv"]'),
CleanText('//ul[@class="prevision-horaire "]/li[@class=" active "]/div/ul/li[@class="day-summary-wind"]'))
def obj_wind_speed(self):
return float(Dict('properties/forecast/{}/wind_speed'.format(self.cpt), default=0)(self))
def obj_humidity(self):
return float(Dict('properties/forecast/{}/relative_humidity'.format(self.cpt), default=0)(self))
def obj_pressure(self):
return float(Dict('properties/forecast/{}/P_sea'.format(self.cpt), default=0)(self))
def obj_temp(self):
temp = CleanDecimal('//ul[@class="prevision-horaire "]/li[@class=" active "]/ul/li[@class="day-summary-temperature"]')(self)
unit = Regexp(CleanText('//ul[@class="prevision-horaire "]/li[@class=" active "]/ul/li[@class="day-summary-temperature"]'),
u'.*\xb0(\w)')(self)
return Temperature(float(temp), unit)
return Temperature(float(Dict('properties/forecast/{}/T'.format(self.cpt), default=50)(self)), 'C')
@method
class iter_forecast(DictElement):
item_xpath = 'properties/daily_forecast'
class item(ItemElement):
klass = Forecast
obj_id = Dict('time')
obj_date = Field('id')
def obj_low(self):
return Temperature(float(Dict('T_min', default=-50)(self)), 'C')
def obj_high(self):
return Temperature(float(Dict('T_max', default=50)(self)), 'C')
def obj_text(self):
return Format(u'%s - humidity %s%% / %s%% - UV index %s',
Dict('daily_weather_description'),
Dict('relative_humidity_min'),
Dict('relative_humidity_max'),
Dict('uv_index'))(self)
......@@ -25,13 +25,16 @@ class MeteoFranceTest(BackendTest):
MODULE = 'meteofrance'
def test_meteofrance(self):
l = list(self.backend.iter_city_search('paris'))
self.assertTrue(len(l) > 0)
cities = list(self.backend.iter_city_search('paris'))
self.assertTrue(len(cities) > 0)
city = l[0]
city = cities[0]
current = self.backend.get_current(city.id)
self.assertTrue(current.temp.value > -20 and current.temp.value < 50)
current2 = self.backend.get_current('béthune')
self.assertTrue(current2.temp.value > -20 and current2.temp.value < 50)
forecasts = list(self.backend.iter_forecast(city.id))
self.assertTrue(len(forecasts) > 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment