223 lines
8.1 KiB
TypeScript
223 lines
8.1 KiB
TypeScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
import { downloadListOfUrls, extractUrls, URL_WITH_COMMAS_REGEX } from '@crawlee/utils';
|
|
|
|
vitest.mock('@crawlee/utils/src/internals/gotScraping', async () => {
|
|
return {
|
|
gotScraping: vitest.fn(),
|
|
};
|
|
});
|
|
|
|
const baseDataPath = path.join(__dirname, '..', 'shared', 'data');
|
|
|
|
describe('downloadListOfUrls()', () => {
|
|
test('downloads a list of URLs', async () => {
|
|
const text = fs.readFileSync(path.join(baseDataPath, 'simple_url_list.txt'), 'utf8');
|
|
const arr = text
|
|
.trim()
|
|
.split(/[\r\n]+/g)
|
|
.map((u) => u.trim());
|
|
|
|
// @ts-ignore for some reason, this fails when the project is not built :/
|
|
const { gotScraping } = await import('@crawlee/utils');
|
|
const gotScrapingSpy = vitest.mocked(gotScraping);
|
|
gotScrapingSpy.mockResolvedValueOnce({ body: text });
|
|
|
|
await expect(
|
|
downloadListOfUrls({
|
|
url: 'http://www.nowhere12345.com',
|
|
}),
|
|
).resolves.toEqual(arr);
|
|
});
|
|
});
|
|
|
|
describe('extractUrls()', () => {
|
|
const SIMPLE_URL_LIST = 'simple_url_list.txt';
|
|
const UNICODE_URL_LIST = 'unicode_url_list.txt';
|
|
const COMMA_URL_LIST = 'unicode+comma_url_list.txt';
|
|
const TRICKY_URL_LIST = 'tricky_url_list.txt';
|
|
const INVALID_URL_LIST = 'invalid_url_list.txt';
|
|
|
|
const getURLData = (filename: string) => {
|
|
const string = fs.readFileSync(path.join(baseDataPath, filename), 'utf8');
|
|
const array = string
|
|
.trim()
|
|
.split(/[\r\n]+/g)
|
|
.map((u) => u.trim());
|
|
return { string, array };
|
|
};
|
|
|
|
const makeJSON = ({ string, array }: { string: string; array: string[] }) =>
|
|
JSON.stringify({
|
|
one: [{ http: string }],
|
|
two: array.map((url) => ({ num: 123, url })),
|
|
});
|
|
|
|
const makeCSV = (array: string[], delimiter?: string) =>
|
|
array.map((url) => ['ABC', 233, url, '.'].join(delimiter || ',')).join('\n');
|
|
|
|
const makeText = (array: string[]) => {
|
|
const text = fs.readFileSync(path.join(baseDataPath, 'lipsum.txt'), 'utf8').split('');
|
|
const ID = 'ů';
|
|
const maxIndex = text.length - 1;
|
|
array.forEach((__, index) => {
|
|
const indexInText = (index * 17) % maxIndex;
|
|
if (text[indexInText] === ID) {
|
|
text[indexInText + 1] = ID;
|
|
} else {
|
|
text[indexInText] = ID;
|
|
}
|
|
});
|
|
return array.reduce((string, url) => string.replace(ID, ` ${url} `), text.join(''));
|
|
};
|
|
|
|
test('extracts simple URLs', () => {
|
|
const { string, array } = getURLData(SIMPLE_URL_LIST);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs', () => {
|
|
const { string, array } = getURLData(UNICODE_URL_LIST);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs with commas', () => {
|
|
const { string, array } = getURLData(COMMA_URL_LIST);
|
|
const extracted = extractUrls({ string, urlRegExp: URL_WITH_COMMAS_REGEX });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts tricky URLs', () => {
|
|
const { string, array } = getURLData(TRICKY_URL_LIST);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
// https://github.com/apify/crawlee/issues/2755
|
|
test('extracts URLs with apostrophes in the path', () => {
|
|
const url = "https://www.zillow.com/homedetails/141-O'Canoe-Pl-Hertford-NC-27944/74398007_zpid/";
|
|
const extracted = extractUrls({ string: url });
|
|
expect(extracted).toEqual([url]);
|
|
});
|
|
|
|
test('extracts URLs with asterisks in the path', () => {
|
|
const url = 'https://example.com/path*star/end';
|
|
const extracted = extractUrls({ string: url });
|
|
expect(extracted).toEqual([url]);
|
|
});
|
|
|
|
test('does not extract invalid URLs', () => {
|
|
const { string } = getURLData(INVALID_URL_LIST);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(['http://www.foo.bar']);
|
|
});
|
|
|
|
test('extracts simple URLs from JSON', () => {
|
|
const d = getURLData(SIMPLE_URL_LIST);
|
|
const string = makeJSON(d);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(d.array.concat(d.array));
|
|
});
|
|
|
|
test('extracts unicode URLs from JSON', () => {
|
|
const d = getURLData(UNICODE_URL_LIST);
|
|
const string = makeJSON(d);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(d.array.concat(d.array));
|
|
});
|
|
|
|
test('extracts unicode URLs with commas from JSON', () => {
|
|
const d = getURLData(COMMA_URL_LIST);
|
|
const string = makeJSON(d);
|
|
const extracted = extractUrls({ string, urlRegExp: URL_WITH_COMMAS_REGEX });
|
|
expect(extracted).toEqual(d.array.concat(d.array));
|
|
});
|
|
|
|
test('extracts tricky URLs from JSON', () => {
|
|
const d = getURLData(TRICKY_URL_LIST);
|
|
const string = makeJSON(d);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(d.array.concat(d.array));
|
|
});
|
|
|
|
test('does not extract invalid URLs from JSON', () => {
|
|
const d = getURLData(INVALID_URL_LIST);
|
|
const string = makeJSON(d);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(['http://www.foo.bar', 'http://www.foo.bar']);
|
|
});
|
|
|
|
test('extracts simple URLs from CSV', () => {
|
|
const { array } = getURLData(SIMPLE_URL_LIST);
|
|
const string = makeCSV(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs from CSV', () => {
|
|
const { array } = getURLData(UNICODE_URL_LIST);
|
|
const string = makeCSV(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs with commas from semicolon CSV', () => {
|
|
const { array } = getURLData(COMMA_URL_LIST);
|
|
const string = makeCSV(array, ';');
|
|
const extracted = extractUrls({ string, urlRegExp: URL_WITH_COMMAS_REGEX });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts tricky URLs from CSV', () => {
|
|
const { array } = getURLData(TRICKY_URL_LIST);
|
|
const string = makeCSV(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('does not extract invalid URLs from CSV', () => {
|
|
const { array } = getURLData(INVALID_URL_LIST);
|
|
const string = makeCSV(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(['http://www.foo.bar']);
|
|
});
|
|
|
|
test('extracts simple URLs from Text', () => {
|
|
const { array } = getURLData(SIMPLE_URL_LIST);
|
|
const string = makeText(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs from Text', () => {
|
|
const { array } = getURLData(UNICODE_URL_LIST);
|
|
const string = makeText(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts unicode URLs with commas from Text', () => {
|
|
const { array } = getURLData(COMMA_URL_LIST);
|
|
const string = makeText(array);
|
|
const extracted = extractUrls({ string, urlRegExp: URL_WITH_COMMAS_REGEX });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('extracts tricky URLs from Text', () => {
|
|
const { array } = getURLData(TRICKY_URL_LIST);
|
|
const string = makeText(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(array);
|
|
});
|
|
|
|
test('does not extract invalid URLs from Text', () => {
|
|
const { array } = getURLData(INVALID_URL_LIST);
|
|
const string = makeText(array);
|
|
const extracted = extractUrls({ string });
|
|
expect(extracted).toEqual(['http://www.foo.bar']);
|
|
});
|
|
});
|