@soyaxell09/zenbot-scraper 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soyaxell09/zenbot-scraper",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Scrapers de descarga y búsqueda para bots de WhatsApp — YouTube, TikTok, Instagram, Facebook, Twitter, Pinterest, MediaFire, GitHub, APK, Google Drive, XNXX, PornHub, XVideos, XHamster, Rule34, Screenshot y más.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -54,6 +54,7 @@
54
54
  "@distube/ytdl-core": "^4.16.0",
55
55
  "axios": "^1.6.0",
56
56
  "cheerio": "^1.0.0",
57
+ "node-fetch": "^3.3.2",
57
58
  "form-data": "^4.0.0"
58
59
  },
59
60
  "engines": {
@@ -5,52 +5,51 @@
5
5
  * Deja los créditos we 🗣️
6
6
  */
7
7
 
8
- import axios from 'axios'
9
- import * as cheerio from 'cheerio'
8
+ import axios from 'axios';
9
+ import * as cheerio from 'cheerio';
10
10
 
11
- const HEADERS = {
12
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
13
- }
11
+ const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
12
+ const BASE = 'https://apkpure.net';
13
+ const DL_BASE = 'https://d.apkpure.net';
14
+ const HEADERS = { 'User-Agent': UA, 'Referer': BASE };
14
15
 
15
16
  function extractPkg(href) {
16
- const m = href?.match(/\/((?:com|org|net|io|co)\.[a-z0-9.]+)(?:\/|$)/i)
17
- return m ? m[1] : ''
17
+ const m = href?.match(/\/((?:com|org|net|io|co)\.[a-z0-9.]+)(?:\/|$)/i);
18
+ return m ? m[1] : '';
18
19
  }
19
20
 
20
- async function searchPage(query) {
21
- const res = await axios.get(
22
- `https://apkpure.com/search?q=${encodeURIComponent(query)}`,
23
- { headers: HEADERS, timeout: 15000 }
24
- )
25
- return cheerio.load(res.data)
21
+ function parsePageData(data) {
22
+ try {
23
+ const m = data.match(/window\.apkpure\s*=\s*\{pageData:\s*(\{.*?\})\s*[,;]/s);
24
+ if (m) return JSON.parse(m[1]);
25
+ } catch {}
26
+ return null;
26
27
  }
27
28
 
28
29
  export async function apkSearch(query, limit = 5) {
29
- if (!query?.trim()) throw new Error('Query vacío')
30
-
31
- const $ = await searchPage(query)
32
- const results = []
33
- const seen = new Set()
34
-
35
- $('.brand-info-top').each((_, el) => {
36
- if (results.length >= limit) return false
30
+ if (!query?.trim()) throw new Error('Query vacío');
37
31
 
38
- const name = $(el).find('.p1').text().trim()
39
- const dev = $(el).find('.p2').text().trim()
40
- const date = $(el).find('.date').text().trim()
41
- const icon = $(el).closest('.search-result').find('img').first().attr('src') || ''
32
+ const { data } = await axios.get(`${BASE}/search?q=${encodeURIComponent(query)}`, {
33
+ headers: HEADERS, timeout: 15000
34
+ });
35
+ const $ = cheerio.load(data);
36
+ const results = [];
37
+ const seen = new Set();
42
38
 
43
- const appHref = $(el).closest('.search-result')
44
- .find('a[href]').toArray()
45
- .map(a => $(a).attr('href'))
46
- .find(h => extractPkg(h)) || ''
39
+ $('.search-brand-container').each((_, el) => {
40
+ if (results.length >= limit) return false;
47
41
 
48
- const pkg = extractPkg(appHref)
49
- if (!name || !pkg || seen.has(pkg)) return
50
- seen.add(pkg)
42
+ const name = $(el).find('a.top').first().text().trim();
43
+ const dev = $(el).find('a.developer').first().text().trim();
44
+ const date = $(el).find('span.time').first().text().trim();
45
+ const icon = $(el).find('img.app-icon-img').first().attr('data-original') || '';
46
+ const appHref = $(el).find('a.top').first().attr('href') || '';
47
+ const pkg = extractPkg(appHref);
51
48
 
52
- const appUrl = appHref.startsWith('http') ? appHref : `https://apkpure.com${appHref}`
49
+ if (!name || !pkg || seen.has(pkg)) return;
50
+ seen.add(pkg);
53
51
 
52
+ const appUrl = appHref.startsWith('http') ? appHref : `${BASE}${appHref}`;
54
53
  results.push({
55
54
  name,
56
55
  developer: dev,
@@ -58,55 +57,50 @@ export async function apkSearch(query, limit = 5) {
58
57
  date,
59
58
  icon,
60
59
  appUrl,
61
- dlUrl: `https://d.apkpure.com/b/XAPK/${pkg}?version=latest`,
62
- })
63
- })
60
+ dlUrl: `${DL_BASE}/b/APK/${pkg}?version=latest`,
61
+ });
62
+ });
64
63
 
65
- if (!results.length) throw new Error('No se encontraron resultados')
66
- return results
64
+ if (!results.length) throw new Error('No se encontraron resultados');
65
+ return results;
67
66
  }
68
67
 
69
68
  export async function apkInfo(pkgOrUrl) {
70
- let pkg = pkgOrUrl
71
- if (pkgOrUrl.includes('apkpure.com')) {
72
- pkg = extractPkg(pkgOrUrl) || pkgOrUrl
73
- }
74
-
75
- // Buscar por última parte del pkg (ej: "whatsapp" de "com.whatsapp")
76
- const shortName = pkg.split('.').pop()
77
- const $ = await searchPage(shortName)
78
-
79
- // Buscar el item que tenga el pkg correcto
80
- let found = null
81
- $('.brand-info-top').each((_, el) => {
82
- if (found) return false
83
- const appHref = $(el).closest('.search-result')
84
- .find('a[href]').toArray()
85
- .map(a => $(a).attr('href'))
86
- .find(h => h?.includes(pkg))
87
- if (appHref) found = el
88
- })
89
-
90
- const el = found ? $(found) : $('.brand-info-top').first()
91
- const name = el.find('.p1').text().trim()
92
- const dev = el.find('.p2').text().trim()
93
- const date = el.find('.date').text().trim()
94
- const icon = el.closest('.search-result').find('img').first().attr('src') || ''
95
-
96
- const dlLinks = []
97
- $(`a[href*="d.apkpure.com"]`).each((_, a) => {
98
- const href = $(a).attr('href') || ''
99
- if (href.includes(pkg)) dlLinks.push(href)
100
- })
69
+ let pkg = pkgOrUrl.includes('apkpure') ? extractPkg(pkgOrUrl) : pkgOrUrl;
70
+ if (!pkg) pkg = pkgOrUrl;
71
+
72
+ const shortName = pkg.split('.').slice(-2).join('-').toLowerCase();
73
+
74
+ const { data } = await axios.get(`${BASE}/${shortName}/${pkg}/download`, {
75
+ headers: HEADERS, timeout: 15000, validateStatus: () => true
76
+ });
77
+ const $ = cheerio.load(data);
78
+ const pageData = parsePageData(data);
79
+
80
+ const name = pageData?.versionName
81
+ ? $('title').text().split(' APK')[0].replace('Download ', '').trim()
82
+ : $('h1, .title-like').first().text().trim();
83
+ const version = pageData?.versionName || $('[class*="version"]').first().text().trim().match(/[\d.]+/)?.[0] || '';
84
+ const size = $('[class*="size"]').first().text().trim();
85
+ const icon = $('img.icon, img[itemprop="image"]').first().attr('src') || '';
86
+ const dev = $('[class*="developer"], .dev-info, [itemprop="author"]').first().text().trim();
87
+
88
+ const dlLinks = [];
89
+ $(`a[href*="d.apkpure.net"]`).each((_, a) => {
90
+ const href = $(a).attr('href') || '';
91
+ if (href.includes(pkg)) dlLinks.push(href);
92
+ });
101
93
 
102
94
  return {
103
95
  name,
104
96
  developer: dev,
105
97
  pkg,
106
- date,
98
+ version,
99
+ size,
107
100
  icon,
108
- download: `https://d.apkpure.com/b/XAPK/${pkg}?version=latest`,
101
+ download: `${DL_BASE}/b/APK/${pkg}?version=latest`,
102
+ downloadXapk: `${DL_BASE}/b/XAPK/${pkg}?version=latest`,
109
103
  dlLinks: [...new Set(dlLinks)],
110
- url: `https://apkpure.com/search?q=${shortName}`,
111
- }
104
+ url: `${BASE}/${shortName}/${pkg}`,
105
+ };
112
106
  }
@@ -29,26 +29,34 @@ function parseItems(html) {
29
29
  items.push({ type, url: clean });
30
30
  }
31
31
 
32
+ // Primero agregar fuentes directas (CDN Instagram)
32
33
  $('source[src]').each((_, el) => {
33
34
  const src = $(el).attr('src');
34
- if (src) add('video', src);
35
- });
36
-
37
- $('a[href]').each((_, el) => {
38
- const href = $(el).attr('href') || '';
39
- if (!href.includes('kdnsd/v1/download')) return;
40
- const b64 = href.split('url=')[1] || '';
41
- const decoded = decodeUrl(decodeURIComponent(b64));
42
- const type = decoded.includes('.mp4') ? 'video' : 'image';
43
- add(type, href.replace(/&/g, '&'));
35
+ if (src && !src.includes('kdnsd')) add('video', src);
44
36
  });
45
37
 
46
38
  $('img[src]').each((_, el) => {
47
39
  const src = $(el).attr('src') || '';
48
- if (src.includes('kdnsd/v1/download') || src.includes('cdninstagram') || src.includes('fbcdn'))
40
+ if ((src.includes('cdninstagram') || src.includes('fbcdn')) && !src.includes('kdnsd'))
49
41
  add('image', src);
50
42
  });
51
43
 
44
+ if (!items.length) {
45
+ $('a[href]').each((_, el) => {
46
+ const href = $(el).attr('href') || '';
47
+ if (!href.includes('kdnsd/v1/download')) return;
48
+ const b64 = href.split('url=')[1] || '';
49
+ const decoded = decodeUrl(decodeURIComponent(b64));
50
+ const type = decoded.includes('.mp4') ? 'video' : 'image';
51
+ add(type, href.replace(/&/g, '&'));
52
+ });
53
+
54
+ $('img[src]').each((_, el) => {
55
+ const src = $(el).attr('src') || '';
56
+ if (src.includes('kdnsd/v1/download')) add('image', src);
57
+ });
58
+ }
59
+
52
60
  return items;
53
61
  }
54
62