
Build webscraper to collect data from outlet menus
- or -
Post a project like this$125
- Posted:
- Proposals: 26
- Remote
- #4508080
- Expired
Data Entry|Web Research|Scraping|pdf to Word/Excel|QuickBooks|Translator|Admin support


23+ years expert in PHP, MySQL, HTML, CSS, JavaScript, jQuery, Ajax, Bootstrap, Chrome Extension, VB, VBA, AutIT Programming & Website Data Scraping
Integration developer · WooCommerce · Shopify · Stripe · Google APIs · BigQuery · Python · PHP · Available for contract and white-label

Back-Office & BPO Operations Lead | Medical Billing, Payroll, CRM, Data Entry, Web Scraping, & Lead Generation

Full Stack Developer | Next.js | React | TypeScript | Node.js | Python | AI & SaaS
Website Designer|Shopify & WordPress Expert|Brand Identity Design|UI Design / UX Design

AI/ML & Web Development Agency | Automation, Chatbots & Data Science | Designing Team


13343348115751602324765041591106777744304611224715211904576734955812876072667131911973068
Description
Experience Level: Intermediate
I have a list of appr. 50.000 outlets, of which I want to have the menu information scraped cleansed and organised (see FACT DIM below). Assignment is to receive a working and tested code for doing that, perphaps for a smal sample of 100 outlets or so to see that it's working.
Lump sum proposal please, needs to be ready asap.
Best regards,
Sander
--------------
CREATE TABLE public.outlet (
outlet_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
naam text NOT NULL,
plaats text,
website_url text,
segment text,
status text NOT NULL DEFAULT 'actief'::text CHECK (status = ANY (ARRAY['actief'::text, 'inactief'::text])),
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT outlet_pkey PRIMARY KEY (outlet_id)
);
CREATE TABLE public.menu_source (
source_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
outlet_id bigint NOT NULL,
pagina_type text,
url text NOT NULL,
domain text,
bestandstype text CHECK (bestandstype = ANY (ARRAY['html'::text, 'pdf'::text, 'image'::text])),
confidence real,
is_active boolean NOT NULL DEFAULT true,
created_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT menu_source_pkey PRIMARY KEY (source_id),
CONSTRAINT menu_source_outlet_id_fkey FOREIGN KEY (outlet_id) REFERENCES public.outlet(outlet_id)
);
CREATE TABLE public.crawl_run (
run_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
source_id bigint NOT NULL,
crawled_at timestamp with time zone NOT NULL DEFAULT now(),
http_status integer,
etag text,
last_modified text,
sha256 text,
parse_status text NOT NULL DEFAULT 'pending'::text CHECK (parse_status = ANY (ARRAY['pending'::text, 'ok'::text, 'partial'::text, 'failed'::text, 'not_modified'::text])),
parser_version text,
raw_ref text,
CONSTRAINT crawl_run_pkey PRIMARY KEY (run_id),
CONSTRAINT crawl_run_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.menu_source(source_id)
);
CREATE TABLE public.menu_item (
menuitem_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
run_id bigint NOT NULL,
categorie text,
product text NOT NULL,
beschrijving text,
prijs numeric,
valuta text NOT NULL DEFAULT 'EUR'::text,
volume text,
merk text,
merkeigenaar text,
positie integer,
confidence real,
CONSTRAINT menu_item_pkey PRIMARY KEY (menuitem_id),
CONSTRAINT menu_item_run_id_fkey FOREIGN KEY (run_id) REFERENCES public.crawl_run(run_id)
);
CREATE TABLE public.change_event (
event_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
outlet_id bigint NOT NULL,
source_id bigint,
oud_menuitem_id bigint,
nieuw_menuitem_id bigint,
detectiedatum timestamp with time zone NOT NULL DEFAULT now(),
event_type text NOT NULL CHECK (event_type = ANY (ARRAY['product_toegevoegd'::text, 'product_verwijderd'::text, 'prijs_verhoogd'::text, 'prijs_verlaagd'::text, 'brand_switch'::text, 'menu_redesign'::text])),
oude_waarde text,
nieuwe_waarde text,
ai_interpretatie text,
impact text CHECK (impact = ANY (ARRAY['hoog'::text, 'midden'::text, 'laag'::text])),
opportunity_score integer CHECK (opportunity_score >= 0 AND opportunity_score <= 100),
aanbevolen_actie text,
bevestigd_runs integer NOT NULL DEFAULT 1,
status text NOT NULL DEFAULT 'nieuw'::text CHECK (status = ANY (ARRAY['nieuw'::text, 'bekeken'::text, 'afgehandeld'::text, 'false_positive'::text])),
CONSTRAINT change_event_pkey PRIMARY KEY (event_id),
CONSTRAINT change_event_outlet_id_fkey FOREIGN KEY (outlet_id) REFERENCES public.outlet(outlet_id),
CONSTRAINT change_event_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.menu_source(source_id),
CONSTRAINT change_event_oud_menuitem_id_fkey FOREIGN KEY (oud_menuitem_id) REFERENCES public.menu_item(menuitem_id),
CONSTRAINT change_event_nieuw_menuitem_id_fkey FOREIGN KEY (nieuw_menuitem_id) REFERENCES public.menu_item(menuitem_id)
);
Lump sum proposal please, needs to be ready asap.
Best regards,
Sander
--------------
CREATE TABLE public.outlet (
outlet_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
naam text NOT NULL,
plaats text,
website_url text,
segment text,
status text NOT NULL DEFAULT 'actief'::text CHECK (status = ANY (ARRAY['actief'::text, 'inactief'::text])),
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT outlet_pkey PRIMARY KEY (outlet_id)
);
CREATE TABLE public.menu_source (
source_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
outlet_id bigint NOT NULL,
pagina_type text,
url text NOT NULL,
domain text,
bestandstype text CHECK (bestandstype = ANY (ARRAY['html'::text, 'pdf'::text, 'image'::text])),
confidence real,
is_active boolean NOT NULL DEFAULT true,
created_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT menu_source_pkey PRIMARY KEY (source_id),
CONSTRAINT menu_source_outlet_id_fkey FOREIGN KEY (outlet_id) REFERENCES public.outlet(outlet_id)
);
CREATE TABLE public.crawl_run (
run_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
source_id bigint NOT NULL,
crawled_at timestamp with time zone NOT NULL DEFAULT now(),
http_status integer,
etag text,
last_modified text,
sha256 text,
parse_status text NOT NULL DEFAULT 'pending'::text CHECK (parse_status = ANY (ARRAY['pending'::text, 'ok'::text, 'partial'::text, 'failed'::text, 'not_modified'::text])),
parser_version text,
raw_ref text,
CONSTRAINT crawl_run_pkey PRIMARY KEY (run_id),
CONSTRAINT crawl_run_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.menu_source(source_id)
);
CREATE TABLE public.menu_item (
menuitem_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
run_id bigint NOT NULL,
categorie text,
product text NOT NULL,
beschrijving text,
prijs numeric,
valuta text NOT NULL DEFAULT 'EUR'::text,
volume text,
merk text,
merkeigenaar text,
positie integer,
confidence real,
CONSTRAINT menu_item_pkey PRIMARY KEY (menuitem_id),
CONSTRAINT menu_item_run_id_fkey FOREIGN KEY (run_id) REFERENCES public.crawl_run(run_id)
);
CREATE TABLE public.change_event (
event_id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
outlet_id bigint NOT NULL,
source_id bigint,
oud_menuitem_id bigint,
nieuw_menuitem_id bigint,
detectiedatum timestamp with time zone NOT NULL DEFAULT now(),
event_type text NOT NULL CHECK (event_type = ANY (ARRAY['product_toegevoegd'::text, 'product_verwijderd'::text, 'prijs_verhoogd'::text, 'prijs_verlaagd'::text, 'brand_switch'::text, 'menu_redesign'::text])),
oude_waarde text,
nieuwe_waarde text,
ai_interpretatie text,
impact text CHECK (impact = ANY (ARRAY['hoog'::text, 'midden'::text, 'laag'::text])),
opportunity_score integer CHECK (opportunity_score >= 0 AND opportunity_score <= 100),
aanbevolen_actie text,
bevestigd_runs integer NOT NULL DEFAULT 1,
status text NOT NULL DEFAULT 'nieuw'::text CHECK (status = ANY (ARRAY['nieuw'::text, 'bekeken'::text, 'afgehandeld'::text, 'false_positive'::text])),
CONSTRAINT change_event_pkey PRIMARY KEY (event_id),
CONSTRAINT change_event_outlet_id_fkey FOREIGN KEY (outlet_id) REFERENCES public.outlet(outlet_id),
CONSTRAINT change_event_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.menu_source(source_id),
CONSTRAINT change_event_oud_menuitem_id_fkey FOREIGN KEY (oud_menuitem_id) REFERENCES public.menu_item(menuitem_id),
CONSTRAINT change_event_nieuw_menuitem_id_fkey FOREIGN KEY (nieuw_menuitem_id) REFERENCES public.menu_item(menuitem_id)
);
Sander S.
0% (0)Projects Completed
-
Freelancers worked with
-
Projects awarded
0%
Last project
8 Sep 2026
Netherlands
New Proposal
Login to your account and send a proposal now to get this project.
Log inClarification Board Ask a Question
-

A few quick questions:
1. Do you already have the list of 50,000 outlets with their website URLs in your database?
2. Should the scraper also handle JavaScript-based menu pages (React/Vue websites)?
3. Will the final solution run on your server, or would you like Docker setup and deployment instructions as well?
-

All menu are available on same site?
-

Will the list of 50,000 outlets already include website URLs, or should the scraper also discover menu source URLs as part of the workflow?
115823911582381158236
We collect cookies to enable the proper functioning and security of our website, and to enhance your experience. By clicking on 'Accept All Cookies', you consent to the use of these cookies. You can change your 'Cookies Settings' at any time. For more information, please read ourCookie Policy
Cookie Settings
Accept All Cookies