-
Notifications
You must be signed in to change notification settings - Fork 9.6k
feat(route): Add routes for ebay #21323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
cfc0cab
d3ff772
f5ad403
449def2
ec93a56
878edce
edf35d0
826359a
a99c86c
1233ae7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import type { Namespace } from '@/types'; | ||
|
|
||
| export const namespace: Namespace = { | ||
| name: 'eBay', | ||
| url: 'ebay.com', | ||
| categories: ['shopping'], | ||
| description: 'eBay search results and user listings.', | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import { load } from 'cheerio'; | ||
|
|
||
| import type { Route } from '@/types'; | ||
| import logger from '@/utils/logger'; | ||
| import ofetch from '@/utils/ofetch'; | ||
|
|
||
| export const route: Route = { | ||
| path: '/search/:keywords', | ||
| categories: ['shopping'], | ||
| example: '/ebay/search/sodimm+ddr4+16gb', | ||
| parameters: { keywords: 'Keywords for search' }, | ||
| features: { | ||
| requireConfig: false, | ||
| requirePuppeteer: false, | ||
| antiCrawler: false, | ||
| supportBT: false, | ||
| supportPodcast: false, | ||
| supportScihub: false, | ||
| }, | ||
| radar: [ | ||
| { | ||
| source: ['ebay.com/sch/i.html'], | ||
| target: (params, url) => { | ||
| const searchKeywords = new URL(url).searchParams.get('_nkw'); | ||
| return `/ebay/search/${searchKeywords}`; | ||
| }, | ||
| }, | ||
| ], | ||
| name: 'Search Results', | ||
| maintainers: ['phoeagon'], | ||
| handler: async (ctx) => { | ||
| const { keywords } = ctx.req.param(); | ||
| const url = `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(keywords)}&_sop=10&_ipg=240`; | ||
|
|
||
| const response = await ofetch(url); | ||
| const $ = load(response); | ||
|
|
||
| const items = $('.srp-results .s-item, .srp-results .s-card, .s-card') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If removing the selector does work then don't include it in the first place as this means it is redundant. |
||
| .toArray() | ||
| .map((item) => { | ||
| const $item = $(item); | ||
| const titleElement = $item.find('.s-item__title, .s-card__title, .s-item__title--has-tags'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide an example that the site does have |
||
| const title = titleElement.text().replace(/^new listing/i, '').trim(); | ||
| const link = $item.find('.s-item__link, .s-card__link').attr('href'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide an example that the site does have |
||
| const price = $item.find('.s-item__price, .s-card__price').text().trim(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide an example that the site does have |
||
| const imageElement = $item.find('.s-item__image-img img, img.s-item__image-img, .s-item__image-wrapper img, .s-card__image-img img, .s-item__image img, .s-card__link img'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide an example that the site does have |
||
| const image = imageElement.attr('data-src') || imageElement.attr('src'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide an example that the site does have img URLs appears only in the |
||
|
|
||
| if (!title || !link || title.toLowerCase().includes('shop on ebay') || price === '') { | ||
| return null; | ||
| } | ||
|
|
||
| const cleanedLink = new URL(link); | ||
| cleanedLink.search = ''; | ||
|
|
||
| return { | ||
| title: `${title} - ${price}`, | ||
| link: cleanedLink.toString(), | ||
| description: `<img src="${image?.replace(/\.jpe?g$/i, '.webp')}"><br>Price: ${price}`, | ||
| }; | ||
| }) | ||
| .filter(Boolean); | ||
|
|
||
| logger.info(`Found ${items.length} items on eBay`); | ||
|
|
||
| return { | ||
| title: `eBay Search: ${keywords}`, | ||
| link: url, | ||
| item: items, | ||
| }; | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { load } from 'cheerio'; | ||
|
||
|
|
||
| import type { Route } from '@/types'; | ||
| import ofetch from '@/utils/ofetch'; | ||
|
|
||
| export const route: Route = { | ||
| path: ['/user/:username'], | ||
| categories: ['shopping'], | ||
| example: '/ebay/user/m.trotters', | ||
| parameters: { username: 'Username of the seller' }, | ||
| features: { | ||
| requireConfig: false, | ||
| requirePuppeteer: false, | ||
| antiCrawler: false, | ||
| supportBT: false, | ||
| supportPodcast: false, | ||
| supportScihub: false, | ||
| }, | ||
| radar: [ | ||
| { | ||
| source: ['ebay.com/usr/'], | ||
| target: '/user/:username', | ||
| }, | ||
| ], | ||
| name: 'User Listings', | ||
| maintainers: ['phoeagon'], | ||
| handler: async (ctx) => { | ||
| const { username } = ctx.req.param(); | ||
| const url = `https://www.ebay.com/usr/${username}`; | ||
|
|
||
| const response = await ofetch(url); | ||
| const $ = load(response); | ||
|
|
||
| const items = $('article.str-item-card.StoreFrontItemCard') | ||
| .toArray() | ||
| .map((item) => { | ||
| const $item = $(item); | ||
| const title = $item.find('.str-card-title .str-text-span').first().text().trim(); | ||
| const link = $item.find('.str-item-card__link').attr('href'); | ||
| const price = $item.find('.str-item-card__property-displayPrice').text().trim(); | ||
| const image = $item.find('.str-image img').attr('src'); | ||
|
|
||
| if (!title || !link) { | ||
| return null; | ||
| } | ||
|
|
||
| const cleanedLink = new URL(link); | ||
| cleanedLink.search = ''; | ||
|
|
||
| return { | ||
| title: `${title} - ${price}`, | ||
| link: cleanedLink.toString(), | ||
| description: `<img src="${image?.replace(/\.jpe?g$/i, '.webp')}"><br>Price: ${price}`, | ||
| author: username, | ||
| }; | ||
| }) | ||
| .filter(Boolean); | ||
|
|
||
| return { | ||
| title: `eBay User: ${username}`, | ||
| link: url, | ||
| item: items, | ||
| }; | ||
| }, | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.