mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-19 06:38:55 +08:00
Add Hopper (#474)
This commit is contained in:
@@ -1825,3 +1825,19 @@ nearby: 可选 0 或 1,默认 0 为不包括,是否包括临近机场
|
||||
|
||||
1. 简单模式,例如「data visualization」,[https://rsshub.app/google/scholar/data+visualization](https://rsshub.app/google/scholar/data+visualization)。
|
||||
2. 高级模式,前往 [Google Scholar](https://scholar.google.com/schhp?hl=zh-cn&as_sdt=0,5),点击左上角,选择高级搜索并提交查询。此时 URL 应为:[https://scholar.google.com/scholar?as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=zh-CN&as_sdt=0%2C5](https://scholar.google.com/scholar?as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=zh-CN&as_sdt=0%2C5),复制`https://scholar.google.com/scholar?`后的所有语句作为本路由的查询参数。例子所对应的完整路由为[https://rsshub.app/google/scholar/as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=zh-CN&as_sdt=0%2C5](https://rsshub.app/google/scholar/as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=zh-CN&as_sdt=0%2C5)。
|
||||
|
||||
## Hopper Flight Deals
|
||||
|
||||
### Hopper 特价机票 <Author uid="HenryQW"/>
|
||||
|
||||
举例: 伦敦希思罗 ✈ 北京首都国际 [https://rsshub.app/hopper/LHR/PEK](https://rsshub.app/hopper/LHR/PEK)
|
||||
|
||||
路由: `/hopper/:from/:to?`
|
||||
|
||||
参数:
|
||||
|
||||
from: 始发地,IATA 国际航空运输协会机场代码
|
||||
|
||||
to: 目的地,IATA 国际航空运输协会机场代码,可选,缺省则目的地为`任意城市`
|
||||
|
||||
IATA 国际航空运输协会机场代码,参见[维基百科 国际航空运输协会机场代码](<https://zh.wikipedia.org/wiki/%E5%9B%BD%E9%99%85%E8%88%AA%E7%A9%BA%E8%BF%90%E8%BE%93%E5%8D%8F%E4%BC%9A%E6%9C%BA%E5%9C%BA%E4%BB%A3%E7%A0%81_(A)>)
|
||||
|
||||
@@ -308,8 +308,11 @@ Eg: [https://rsshub.app/github/issue/DIYgod/RSSHub](https://rsshub.app/github/is
|
||||
|
||||
Route: `/github/issue/:user/:repo`
|
||||
|
||||
Parameters: user, username
|
||||
Parameters: repo, repo name
|
||||
Parameters:
|
||||
|
||||
user, username
|
||||
|
||||
repo, repo name
|
||||
|
||||
## EZTV
|
||||
|
||||
@@ -366,7 +369,7 @@ locations: the departing city, consists of an 「ISO 3166-1 country code」 and
|
||||
1. Origin's ISO 3166-1 country code + city name, eg. `us+new york`, [https://rsshub.app/atfd/us+new york](https://rsshub.app/atfd/us+new%20york)
|
||||
2. Multiple origins are support via a comma separated string, eg. `us+new york,gb+london`, [https://rsshub.app/atfd/us+new york,gb+london/](https://rsshub.app/atfd/us+new%20york,gb+london/)
|
||||
|
||||
For ISO 3166-1 country codes please refer to [wikipedia ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1)
|
||||
For ISO 3166-1 country codes please refer to [Wikipedia ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1)
|
||||
|
||||
nearby: whether includes nearby airports, optional value of 0 or 1, default to 0 (exclude nearby airports)
|
||||
|
||||
@@ -389,3 +392,19 @@ Parameters: query, query statement which supports「Basic」and「Advanced」mod
|
||||
1. Basic mode, sample query is the keywords desired, eg.「data visualization」, [https://rsshub.app/google/scholar/data+visualization](https://rsshub.app/google/scholar/data+visualization).
|
||||
|
||||
2. Advanced mode, visit [Google Scholar](https://scholar.google.com/schhp?hl=en&as_sdt=0,5), click the top left corner and select「Advanced Search」, fill in your conditions and submit the search. The URL should look like this: [https://scholar.google.com/scholar?as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=en&as_sdt=0%2C5](https://scholar.google.com/scholar?as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=en&as_sdt=0%2C5), copy everything after `https://scholar.google.com/scholar?` from the URL and use it as the query for this route. The complete URL for the above example should look like this: [https://rsshub.app/google/scholar/as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=en&as_sdt=0%2C5](https://rsshub.app/google/scholar/as_q=data+visualization&as_epq=&as_oq=&as_eq=&as_occt=any&as_sauthors=&as_publication=&as_ylo=2018&as_yhi=&hl=en&as_sdt=0%2C5).
|
||||
|
||||
## Hopper
|
||||
|
||||
### Hopper Flight Deals <Author uid="HenryQW"/>
|
||||
|
||||
Eg: London Heathrow Airport ✈ Beijing Capital International Airport [https://rsshub.app/hopper/LHR/PEK](https://rsshub.app/hopper/LHR/PEK)
|
||||
|
||||
Route: `/hopper/:from/:to?`
|
||||
|
||||
Parameters:
|
||||
|
||||
from, origin airport IATA code
|
||||
|
||||
to, destination airport IATA code, optional, if unset the destination will be set to `anywhere`
|
||||
|
||||
For airport IATA code please refer to [Wikipedia List of airports by IATA code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_code:_A)
|
||||
|
||||
@@ -414,4 +414,7 @@ router.get('/fir/update/:id', require('./routes/fir/update'));
|
||||
// Google
|
||||
router.get('/google/scholar/:query', require('./routes/google/scholar'));
|
||||
|
||||
// Hopper
|
||||
router.get('/hopper/:from/:to?', require('./routes/hopper/index'));
|
||||
|
||||
module.exports = router;
|
||||
|
||||
77
routes/hopper/index.js
Normal file
77
routes/hopper/index.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const axios = require('../../utils/axios');
|
||||
const config = require('../../config');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const from = ctx.params.from;
|
||||
const to = ctx.params.to || 'Anywhere';
|
||||
|
||||
const url = `https://www.hopper.com/deals/best/from/${from}/to/${to}`;
|
||||
const title = `Hopper - Flights From ${from} to ${to}`;
|
||||
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url,
|
||||
headers: {
|
||||
'User-Agent': config.ua,
|
||||
},
|
||||
params: {
|
||||
pid: 'website',
|
||||
c: 'flexweb',
|
||||
},
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('div.prices li a');
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
link: url,
|
||||
description: title,
|
||||
item: list
|
||||
.map((i, e) => {
|
||||
const item = $(e).attr('href');
|
||||
let reg = new RegExp('destination=(.*?)&', 'g');
|
||||
const destination = reg.exec(item)[1];
|
||||
reg = new RegExp('origin=(.*?)&', 'g');
|
||||
const origin = reg.exec(item)[1];
|
||||
reg = new RegExp('departureDate=(.*?)&', 'g');
|
||||
const departureDate = reg.exec(item)[1];
|
||||
reg = new RegExp('returnDate=(.*?)&', 'g');
|
||||
const returnDate = reg.exec(item)[1];
|
||||
|
||||
const price = $(list[i])
|
||||
.find('.price')
|
||||
.text();
|
||||
|
||||
const title = `${origin} ✈ ${destination} ${getMonthYear(departureDate)} for ${price}`;
|
||||
|
||||
const description = `<table><tbody><tr><th align="left" style="border: 1px solid black;">From</th><th align="left" style="border: 1px solid black;">To</th><th align="left" style="border: 1px solid black;">Price</th></tr><tr><td style="border: 1px solid black;">
|
||||
${origin}</td><td style="border: 1px solid black;">${destination}</td><td style="border: 1px solid black;">${price}</td></tr></tbody></table>${formatDate(departureDate)} ✈ ${formatDate(returnDate)}`;
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
guid: item,
|
||||
link: item,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
};
|
||||
};
|
||||
|
||||
function formatDate(v) {
|
||||
return new Intl.DateTimeFormat('en-gb', {
|
||||
year: 'numeric',
|
||||
weekday: 'short',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
}).format(new Date(v));
|
||||
}
|
||||
|
||||
function getMonthYear(v) {
|
||||
const date = new Date(v);
|
||||
return date.toLocaleString('en-gb', {
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user