104 Taiwan Jobs
Pricing
$0.63 / 1,000 results
104 Taiwan Jobs
Pricing
$0.63 / 1,000 results
Rating
0.0
(0)
Developer
Stone Jade
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Collect public job listings from 104.com.tw for recruiting research, salary analysis and hiring-market monitoring. Search multiple keywords, filter by area and job category, and export unique jobs to an Apify dataset. Optional detail requests add qualifications, benefits and work conditions. Recruiter contacts are omitted.
The Actor is job104-taiwan-jobs, uses Node.js ESM, and defaults to 128 MB.
Example results
These values come from the recorded research fixture list_ps30.json; they are
examples, not a promise that a job is still available.
| Field | Example |
|---|---|
jobCode | 89sn1 |
jobNo | 13893949 |
jobName | <韌體工程師> Firmware Engineer 物聯網無線模組產業 |
custName | 勁達國際電子股份有限公司 |
jobAddrNoDesc | 新北市中和區 |
salaryLow, salaryHigh | 0, 0 (negotiable in this listing) |
url | https://www.104.com.tw/job/89sn1 |
Results keep useful native 104 list field names: jobName, custName, custNo,
appearDate, jobCat, industry, address, coordinates, salary bounds, description,
education codes and remote-work type. Publication dates use ISO YYYY-MM-DD in both list and detail fields.
Uncapped salary maxima (9999999) become null, with salaryMaxUnbounded: true.
salaryType preserves the source type code (list s10); salaryUnit is
piece, hour, day, month, year, or null for negotiable/unknown types. Zero salary
bounds remain source values; no salary amounts are estimated.
With fetchDetails=true, results also contain header, jobDetail, condition,
welfare and company objects, including salary bounds, work location,
requirements, benefits and job description. Recruiter contact fields and viewer
state are omitted. Email, Taiwan phone patterns and labeled recruiter names in
free text are masked, including when the legacy includeContact option is true.
Masking applies only to description, other-condition text, and welfare text.
Codes, IDs, URLs, coordinates and other structured fields retain their source values.
Free-text masking is heuristic and cannot recognize every possible personal detail.
The full output schema is in .actor/dataset_schema.json.
Inputs
| Input | Default | Meaning |
|---|---|---|
keywords | [] | Separate OR searches, e.g. ["python", "資料分析"]; empty searches all jobs. |
areaCodes | [] | Ten-digit strings, e.g. ["6001001000"] for Taipei City; empty is unrestricted. |
jobCategoryCodes | [] | Ten-digit strings, e.g. ["2007000000"] for IT/software; empty is unrestricted. |
maxItems | 50 | Positive integer; global maximum unique saved jobs across all searches. |
fetchDetails | false | One extra detail request per new unique job. |
detailConcurrency | 3 | Maximum simultaneous details; drops to 1 for the rest of the run after a 429. |
includeContact | false | Deprecated compatibility option; contact output remains disabled. |
useProxy | "none" | "none" or "datacenter"; datacenter uses Actor.createProxyConfiguration({ groups: [] }). |
{"keywords": ["python"],"areaCodes": ["6001001000"],"jobCategoryCodes": ["2007000000"],"maxItems": 50,"fetchDetails": false,"includeContact": false,"useProxy": "none"}
Public code trees: areas
and job categories.
Copies recorded with the research samples are bundled in data/. These support
automatic query splitting without downloading code lists during each run.
Unknown ten-digit codes can be submitted but have no known descendants for splitting.
Pagination and limits
Every list request uses pagesize=30. 104 may return two extra promoted jobs;
all returned rows are considered and deduplicated globally by jobNo.
The Actor stops at the response's lastPage, including clamped final pages.
104 caps many searches at about 3,000 results. If more jobs are needed after the
first page, a query with total > lastPage * 30 is split into area × category slices. Supplied
code arrays are separated, and capped single branches are recursively refined
using the bundled trees. An unrestricted capped query starts with the eight
area roots × eighteen category roots. Capped children are split into sub-areas
and sub-categories until pageable or no descendants remain.
The global item limit still applies. Parent and slice overlaps are deduplicated.
If a capped leaf or unknown code cannot be refined, the Actor reads its available
pages and records OUTPUT.cappedQueries plus a warning. It does not guarantee
exhaustive coverage of these slices. Jobs may change while a run is in progress;
the site does not provide a consistent snapshot.
List requests are serial. Details use up to detailConcurrency workers, with
one second between all request starts, including retries. After a 429, already
running details drain and subsequent jobs run one at a time.
Only the remaining gap is waited: a response taking over a second adds no sleep.
Robots crawl delays, retry backoff and Retry-After add no sleeps. HTTP 403/429
and network failures retry at most twice at the same one-second start gap;
each request has a 30-second timeout. Other HTTP
errors, redirects, malformed payloads or unavailable details fail the run.
A run that saves zero jobs fails, including genuinely empty searches, except
when collection stops at the Actor deadline.
Already saved jobs remain available if a later request fails.
When ACTOR_TIMEOUT_AT or Actor.getEnv().timeoutAt provides a deadline,
collection stops 15 seconds before it. Pending target requests are aborted;
saved dataset items remain available and OUTPUT is written before exit.
The final Detail and memory summary logs http429Count (429 responses only),
averageDetailMs (per-job detail elapsed time including waits and retries), and
memoryPeakRssBytes. RSS is sampled with process.memoryUsage().rss every five
seconds and at run start/end. These metrics are also stored in OUTPUT.
OUTPUT records item/request counts, list pages, detail requests, deduplicated
rows, retries, rate limits, splits, unrefinable caps, errors, robots disallow hits
and whether the SDK billing limit or timeout margin stopped collection.
The final Query slice summary log and OUTPUT.slices include each slice's
filters, reported total/lastPage, fetched pages, rows before dedupe,
new global job numbers after dedupe, saved items, duplicates and completion status.
totalBeforeDedupe and totalAfterDedupe count all fetched rows and unique
jobNo values across the run. They include any unsaved remainder of a page
when maxItems, billing or the deadline stops saving; items counts saved rows.
OUTPUT.listRequestStats records HTTP attempts, response bytes, cumulative and
maximum HTTP elapsed time, gap waits and status counts. Debug logs show each
list attempt's status, bytes, elapsedMs and waitMs; a separate page log
shows save time and total page time. The final info summary includes averages,
listSaveMs (saving, including optional details) and listPageElapsedMs.
Enable debug logging with APIFY_LOG_LEVEL=DEBUG to diagnose slow list pages.
Billing
Each list page's new validated results are submitted in one
Actor.pushData(arrayOfItems, 'job') call, using the SDK's combined dataset/event
operation with per-item charging. The batch is deduplicated within the page and
across the run, and capped at the remaining maxItems allowance. Duplicates,
empty results and jobs whose requested details fail do not trigger a job event.
Collection stops when the SDK trims the batch or reports a billing limit; only
saved rows count toward items. No separate charge call is used.
Price: $0.000625 per job — $0.625 per 1,000 jobs, with no run-start fee. You pay only for jobs actually saved (duplicates, empty results and jobs whose requested details fail are not charged, as described above), so 1,000 saved jobs cost you $0.625 in total. For comparison, the main 104 scraper on Apify (corvuslab/taiwan104-jobs-scraper) charges $0.00125 per job plus a $0.005 run-start fee, so the same 1,000 jobs cost $1.255 there — about twice as much.
Run locally
npm cimkdir -p storage/key_value_stores/default# Save the JSON example above as storage/key_value_stores/default/INPUT.json.npm startnpm test
Local results are under storage/datasets/default, with counters in the default
key-value store's OUTPUT.json. On Apify, the default dataset can be exported
as JSON, CSV or Excel. Datacenter proxy use requires appropriate Apify proxy
access; direct access is the default. Tests use recorded fixtures and simulated
responses, without live requests or actual billing. See TESTING.md.
Is it legal to scrape 104.com.tw?
This Actor collects publicly visible job listings without logging in or using account cookies. It does not access applicants or private member data. Recruiter contact fields are omitted and recognizable contacts in text are masked. You are responsible for having an appropriate legal basis and for complying with applicable privacy laws, including Taiwan's Personal Data Protection Act, and the site's terms. Consult legal advice for your specific use. See Apify's discussion of web scraping legality.
104's robots.txt disallows search paths in the
research findings. Disallow rules produce one warning per run and increment
OUTPUT.robotsDisallowedHits for each affected endpoint; the Actor continues
as configured with the one-second request start gap.
This is an independent tool, with no affiliation, endorsement or sponsorship by 104 Corporation. Data is provided as received for research and analysis; respect third-party rights when using or republishing descriptions.