Shine Scraper - India Jobs, Salary, Skills & Expiry
Pricing
from $1.83 / 1,000 job returneds
Shine Scraper - India Jobs, Salary, Skills & Expiry
Every job on Shine.com with the salary as two numbers - published on 82% of listings, measured. Plus the skills asked for, the years of experience wanted, every city the role covers, the employer, the industry and the expiry date. Recruiter emails and phone numbers are not collected. Unofficial.
Pricing
from $1.83 / 1,000 job returneds
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
12 hours ago
Last modified
Categories
Share
Pull jobs from Shine.com — one of India's largest job boards — as clean JSON, with the part most job feeds leave out: the salary, on 82% of listings, as two numbers in INR per year.
Unofficial. This Actor is not affiliated with, endorsed by, or sponsored by Shine.com. All product names are trademarks of their respective owners.
No API key. Reads the same public pages a visitor sees.
Why this one is different
Recruiter emails and phone numbers are removed, on purpose
Shine's own page data carries the recruiting contact's personal email address on every listing and a mobile number on most of them — and advertisers often repeat them inside the advert text (Call & Drop Updated cv : 93108… parveen…@gmail.com).
This Actor does not output those fields at all, and it removes email addresses and mobile numbers from the description text as well. Job data, not a contact list. If you need contact data, use a tool that says so.
The salary is there, and it is honest about when it is not
Measured on 80 live listings on 2026-09-04: 66 of 80 (82%) publish a salary. That is far more than most boards.
Shine writes it as text (Rs 14 - 26 Lakh/Yr) and writes the literal string [Salary Hidden] when the employer withheld it. Passing that through would sell you a salary of "[Salary Hidden]", so:
[Salary Hidden]becomesnull— never a zero, never a string pretending to be a numberRs 14 - 26 Lakh/YrbecomessalaryMin: 1400000,salaryMax: 2600000,salaryCurrency: "INR",salaryPeriod: "year"(1 Lakh = 100,000)- any other wording is left as raw text with the numbers
null— a form we have not verified is never guessed into numbers
Codes we have not verified are not translated
Shine marks employment type with a number. Across 80 listings the value was always 1, and the job's own structured data said FULL_TIME — so 1 maps to FULL_TIME and every other code comes back as null with the raw number in employmentTypeCode. A second code (engagementTypeCode) is passed through untranslated because we could not confirm what its values mean.
One request, twenty complete jobs
Shine ships the full job — description, salary, location, experience, expiry — inside the listing page itself. This Actor reads all twenty from that single page, so it never opens individual job pages. 200 jobs costs 10 requests, not 210.
Every city the role covers
A role open in nine cities comes back with all nine in locations. The job's own detail page shows only the first one.
Dates you can actually compare
Shine writes timestamps without a timezone. Its structured data writes the same instant as +05:30, so this Actor attaches India Standard Time rather than letting your database read them as UTC and shift them by five and a half hours. expiresAt tells you whether a vacancy is about to close.
An empty search is an answer, not a silent fallback
A keyword Shine does not have returns zero results with a total count of zero — it never quietly falls back to every job. You get one no-results row saying so, and it is not charged. A page that could not be read at all is a different row (unreadable) carrying the HTTP status.
Input
| Field | Type | Default | Description |
|---|---|---|---|
keyword | string | developer | Job title or skill. Spaces become hyphens |
city | string | — | bangalore, mumbai, delhi, hyderabad, pune… |
maxJobs | integer | 20 | 1-1000. One job = one row = one charged event |
includeDescription | boolean | true | Full advert text, HTML stripped, contacts removed |
keywords | array | — | Keep only jobs containing one of these words |
keywordMatch | string | any | any or all |
excludeKeywords | array | — | Drop jobs containing one of these |
companyNames | array | — | Keep only these employers (partial match) |
minSalary | integer | 0 | INR per year. A job with no published salary is kept |
requireSalary | boolean | false | Drop the ~18% that hide the salary |
postedWithinDays | integer | 0 | 0 = no limit. An unreadable date is kept |
monitoringMode | boolean | false | Return only jobs not returned on a previous run |
resetMonitoringState | boolean | false | One-shot: forget what was already returned |
useProxy | boolean | true | Route through an Apify proxy |
maxPages | integer | 0 | Safety cap; 0 = decide from maxJobs (20 per page) |
{ "keyword": "developer", "city": "bangalore", "maxJobs": 100,"keywords": ["python", "aws"], "keywordMatch": "all","excludeKeywords": ["intern"], "minSalary": 1500000 }
Filters are applied before you are charged
The filters narrow the jobs already read — nothing extra is fetched from Shine, and a job that does not match is never delivered and never charged. If a search returns jobs but none match your filters, you get one unpaid row saying exactly that, so you can tell "the filter was too tight" apart from "the board is empty".
Two of them refuse to guess: a job with no published salary is kept by minSalary (an unknown salary is not a low one), and a job with an unreadable posted date is kept by postedWithinDays. Turn on requireSalary if you want the unknowns dropped.
Monitoring mode turns this into a daily feed
Schedule it and set monitoringMode: true: each run returns only the jobs it has not returned before. The first run returns everything and remembers it. Jobs that were read but filtered out are remembered too, so a later change of filters does not resurrect them as false "new" postings. You pay for new postings, not for the same list every morning.
Measured on 2026-09-04: developer 38,305 jobs nationwide and 4,923 in Bangalore, accountant 12,768, nurse 1,110.
Output
One row per job:
{"source": "shine","jobId": "19506404","url": "https://www.shine.com/jobs/backendsenior-csharp-developer/iquest-management-consultants-pvt-ltd/19506404","title": "Backend (Senior C# Developer)","company": "IQuest Management Consultants Pvt Ltd.","companyId": 694125,"industry": "IT Services & Consulting","locations": ["Bangalore", "Noida", "Chennai", "Hyderabad", "Gurugram", "Kolkata", "Pune", "Mumbai City", "Delhi"],"salaryText": "Rs 8 - 18 Lakh/Yr","salaryMin": 800000,"salaryMax": 1800000,"salaryCurrency": "INR","salaryPeriod": "year","experienceText": "5 to 8 Yrs","experienceMinYears": 5,"experienceMaxYears": 8,"skills": ["sql server", "t-sql", "performance tuning", "c#", ".net"],"employmentType": "FULL_TIME","employmentTypeCode": 1,"engagementTypeCode": 2,"postedAt": "2026-08-28T17:20:00+05:30","expiresAt": "2026-10-27T00:00:00+05:30","description": "…","status": "ok","scrapedAt": "2026-09-04T05:20:05.658Z"}
Rows that are never charged
status | when |
|---|---|
no-results | Shine has no jobs for this search. That is its answer, not a failure |
unreadable | The page could not be read, or its embedded data was missing |
A page whose embedded data cannot be found is reported as unreadable, never as "no jobs" — so a redesign on Shine's side shows up as an error rather than as a quiet, permanent "there are no vacancies".
Pricing
Pay per job returned. Rows that report an empty search or a page that could not be read are not charged. A job that appears twice is dropped before delivery, so it is never charged twice.
Notes
robots.txtwas fetched on 2026-09-04: theUser-agent: *section disallows/api/*,/jobs/1*,/jobs/9*,/job-search/simple/and similar. This Actor reads only/job-search/<keyword>-jobs, which is not disallowed.- Only public pages are read. No login, no API key.