Ë
    fþÔi¬!  ã                  óÄ   — d Z ddlmZ ddlZddlZddlmZ ddlZddlm	Z	 ddl
mZ ddlmZmZ d	d
lmZmZ  ej$                  e«      ZdZe› d�ZdZdZdZ G d„ de«      Zy)uK  Scraper rejestru radcÃ³w prawnych.

Kontekst: oficjalny rejestr KIRP to szukajradcy.pl (kirp.pl/krajowa-wyszukiwarka
osadza ten sam formularz w iframe). szukajradcy.pl/robots.txt blokuje Å›cieÅ¼kÄ™
/search, wiÄ™c bezpoÅ›redni scraping listingu przez `requests` jest niedozwolony.

RozwiÄ…zanie: listing pobieramy przez Apify aktora `apify/web-scraper`, ktÃ³ry
renderuje stronÄ™ w prawdziwej przeglÄ…darce (Apify ma wÅ‚asne zasady compliance
i wÅ‚asnÄ… pulÄ™ proxy). Aktor przechodzi po stronach wynikÃ³w i wyciÄ…ga linki
profili `/lawyers/...`, a nastÄ™pnie z kaÅ¼dego profilu wyciÄ…ga dane kontaktowe.

Tryby pracy (priorytet):
1. `seed_urls=[...]` â€” gotowa lista profili (np. rÄ™czna lub z innego ÅºrÃ³dÅ‚a).
2. Apify (`apify/web-scraper`) â€” domyÅ›lnie, jeÅ›li jest APIFY_API_KEY.
3. Brak â€” loguje ostrzeÅ¼enie i koÅ„czy bez wynikÃ³w.
é    )ÚannotationsN)ÚIterator)ÚBeautifulSoupé   )Úconfig)Úis_billing_errorÚnotify_billing_erroré   )ÚLeadÚScraperSourcezhttps://szukajradcy.plz/searchzprawo rodzinnezhttps://api.apify.com/v2uâ  
async function pageFunction(context) {
    const { request, $, log, enqueueRequest } = context;
    const url = request.url;

    if (url.includes('/lawyers/')) {
        // strona profilu â€” zwracamy surowy tekst, parsowanie po stronie Pythona
        const title = $('h1').first().text().trim();
        const text = $('body').text().replace(/\s+/g, ' ').trim();
        return {
            type: 'profile',
            url,
            title,
            text,
        };
    }

    // strona listingu â€” enqueue profili i kolejnych stron wynikÃ³w
    const links = new Set();
    $('a[href*="/lawyers/"]').each((_, el) => {
        const href = $(el).attr('href');
        if (href) links.add(new URL(href, url).toString());
    });
    for (const profileUrl of links) {
        await enqueueRequest({ url: profileUrl, userData: { label: 'profile' } });
    }
    log.info(`[oirp] listing ${url} â†’ ${links.size} profiles`);
    return null; // listing sam w sobie nie jest rekordem
}
c                  óx   ‡ — e Zd ZdZ	 	 	 	 	 	 d		 	 	 	 	 	 	 	 	 	 	 d
ˆ fd„Zdd„Zdd„Zdd„Zdd„Zdd„Z	dd„Z
ˆ xZS )ÚOirpScraperÚoirpc                ó.  •— t         ‰| �  |¬«       |xs t        j                  | _        |xs t        j
                  | _        |xs g | _        |xs t        j                  | _	        |xs t        j                  | _        t        j                  | _        y )N)Úlimit)ÚsuperÚ__init__r   ÚAPIFY_OIRP_QUERYÚqueryÚAPIFY_OIRP_MAX_PAGESÚ	max_pagesÚ	seed_urlsÚAPIFY_OIRP_ACTORÚactorÚAPIFY_API_KEYÚapi_keyÚAPIFY_OIRP_MAX_ITEMSÚ	max_items)Úselfr   r   r   r   r   r   Ú	__class__s          €ú=/var/www/html/scraper-prawny.klono.ai/scraper/sources/oirp.pyr   zOirpScraper.__init__N   su   ø€ ô 	‰Ñ˜uÐÔ%ØÒ5œf×5Ñ5ˆŒ
Ø"ÒA¤f×&AÑ&AˆŒØ"š bˆŒØÒ5œf×5Ñ5ˆŒ
ØÒ6¤&×"6Ñ"6ˆŒÜ×4Ñ4ˆ�ó    c                óö  — |xs dj                  «       xs d }| j                  |«      }| j                  |«      }d x}x}}	t        j                  d|«      }
|
rœ|
j                  d«      j                  «       }t        j                  d|«      }|re|j                  d«      j                  «       }|j                  d«      j                  «       }|j                  d«      xs dj                  «       xs d }	d }t        j                  d|«      }|r.|j                  d«      j                  «       j                  d«      }|r|r||vr|› d	|› �}n|r|}n	|rd
|› �}ny t        || j                  d|	||||d|i¬«	      S )NÚ zAdres:\s*([^\n]+?)(?:\s{2,}|$)r
   z"(.+?),\s*(\d{2}-\d{3})\s*([^\n,]*)r   é   z<(Kancelaria[^\n]{2,120}?)(?:\s{2,}|Adres:|Telefon|E-?mail|$)z:,.u    â€” zRadca prawny zRadca prawny / prawo rodzinneÚprofile_url)	ÚnameÚsourceÚnameMoreÚcityÚstreetÚ
postalCodeÚemailÚphoneÚextra)	ÚstripÚextract_emailÚextract_phoneÚreÚsearchÚgroupÚrstripr   r'   )r   ÚurlÚtitleÚtextÚperson_namer-   r.   r+   Úpostalr*   ÚmÚaddrÚpmÚ
kancelariaÚkmÚdisplays                   r!   Ú_lead_from_textzOirpScraper._lead_from_text`   st  € Ø’{ ×)Ñ)Ó+Ò3¨tˆà×"Ñ" 4Ó(ˆØ×"Ñ" 4Ó(ˆà!%Ð%ˆÐ%�˜$Ü�I‰IÐ7¸Ó>ˆÙØ—7‘7˜1“:×#Ñ#Ó%ˆDÜ—‘Ð@À$ÓGˆBÙØŸ™ !›×*Ñ*Ó,�ØŸ™ !›×*Ñ*Ó,�ØŸ™ ›Ò) r×0Ñ0Ó2Ò:°d�àˆ
Ü�Y‰YÐVÐX\Ó]ˆÙØŸ™ !›×*Ñ*Ó,×3Ñ3°EÓ:ˆJá™+¨+¸ZÑ*GØ#˜ E¨+¨Ð7‰GÙØ ‰GÙØ% k ]Ð3‰GàäØØ—9‘9Ø4ØØØØØØ  #Ð&ô

ð 
	
r"   c                óò   — | j                  |«      }|€yt        |j                  d«      }|j                  d«      }|r|j	                  dd¬«      nd}|j	                  dd¬«      }| j                  |||«      S )u@   Tryb seed_urls â€” bezpoÅ›rednie pobranie profilu (nie listing).NÚlxmlÚh1ú T)r0   ú
)Úgetr   r9   ÚfindÚget_textrB   )r   r7   ÚrÚsouprE   r8   r9   s          r!   Ú_parse_detail_httpzOirpScraper._parse_detail_httpŠ   sq   € à�H‰H�S‹MˆØˆ9ØÜ˜QŸV™V VÓ,ˆØ�Y‰Y�t‹_ˆÙ02�—‘˜C t�Ô,¸ˆØ�}‰}˜T¨ˆ}Ó.ˆØ×#Ñ# C¨°Ó5Ð5r"   c                ó:   — | j                   j                  dd«      S )Nú/ú~)r   Úreplace)r   s    r!   Ú_actor_pathzOirpScraper._actor_path–   s   € Ø�z‰z×!Ñ! # sÓ+Ð+r"   c           
     óF  — t        d| j                  dz   «      D �cg c],  }dt        › d| j                  j	                  dd«      › d|› �i‘Œ. }}|dt
        › d�igd	t        | j                  | j                  z   d
z   | j                  | j                  z   d
z   ddiddœS c c}w )Nr
   r7   z?query=rF   ú+z&type=t&page=Úpurlz/lawyers/[.*]za[href*="/lawyers/"]é   ÚuseApifyProxyTÚ
PRODUCTION)Ú	startUrlsÚ
pseudoUrlsÚlinkSelectorÚpageFunctionÚmaxRequestsPerCrawlÚmaxPagesPerCrawlÚproxyConfigurationÚrunMode)Úranger   Ú
SEARCH_URLr   rQ   ÚBASEÚ_PAGE_FUNCTIONr   )r   ÚpÚ
start_urlss      r!   Ú_build_apify_inputzOirpScraper._build_apify_input™   sÀ   € ô ˜1˜dŸn™n¨qÑ0Ó1ö
àð ”z�l '¨$¯*©*×*<Ñ*<¸SÀ#Ó*FÐ)GÀ}ÐUVÐTWÐXÒYð
ˆ
ð 
ð
 $àœD˜6 Ð/Ð0ðð 3Ü*Ø#'§>¡>°D·N±NÑ#BÀQÑ#FØ $§¡°·±Ñ ?À!Ñ CØ#2°DÐ"9Ø#ñ
ð 	
ùò	
s   œ1Bc           	     óP  — t         › d| j                  «       › d�}| j                  t        j                  dœ}| j                  «       }t        j                  d| j                  | j                  | j                  «       	 t        j                  |||t        j                  dz   ¬«      }|j                  dk\  ryt        j                  d	|j                  |j                   d d
 «       t#        |j                   |j                  «      r)t%        dd|j                  › d|j                   d d › �«       g S 	 |j'                  «       S # t        j                  $ r"}t        j                  d|«       g cY d }~S d }~ww xY w# t(        $ r"}t        j                  d|«       g cY d }~S d }~ww xY w)Nz/acts/z/run-sync-get-dataset-items)ÚtokenÚtimeoutz:[oirp] Uruchamiam Apify aktora %s (max_items=%d, pages=%d)é   )ÚparamsÚjsonrj   z[oirp] Apify network error: %si�  z[oirp] Apify HTTP %d: %siô  r   zApify HTTP z: i,  z[oirp] Apify invalid JSON: %s)Ú
APIFY_BASErR   r   r   ÚAPIFY_RUN_TIMEOUTrg   ÚlogÚinfor   r   r   ÚrequestsÚpostÚRequestExceptionÚerrorÚstatus_coder9   r   r	   rm   Ú
ValueError)r   r7   rl   ÚpayloadrK   Úes         r!   Ú
_run_apifyzOirpScraper._run_apify«   s[  € Ü�˜F 4×#3Ñ#3Ó#5Ð"6Ð6QÐRˆØŸ<™<´F×4LÑ4LÑMˆØ×)Ñ)Ó+ˆÜ�‰ÐMØ—‘˜TŸ^™^¨T¯^©^ô	=ð	Ü—‘˜c¨&°wÜ&,×&>Ñ&>ÀÑ&CôEˆAð
 �=‰=˜CÒÜ�I‰IÐ0°!·-±-ÀÇÁÈÈÀÔNÜ §¡¨¯©Ô6Ü$ØØ! !§-¡- °°1·6±6¸$¸3°<°.ÐAôð ˆIð	Ø—6‘6“8ˆOøô ×(Ñ(ò 	Ü�I‰IÐ6¸Ô:Ø�Iûð	ûô ò 	Ü�I‰IÐ5°qÔ9Ø�Iûð	ús<   Á?*E Ä2E: ÅE7ÅE2Å,E7Å2E7Å:	F%ÆF ÆF%Æ F%c              #  óL  K  — d}t        «       }| j                  rr| j                  D ]b  }| j                  r|| j                  k\  r y ||v rŒ%|j                  |«       | j	                  |«      }|r|j                  «       sŒZ|dz  }|–— Œd y | j                  st        j                  d«       y | j                  «       }t        j                  dt        |«      «       |D ]À  }| j                  r|| j                  k\  r y t        |t        «      r|j                  d«      dk7  rŒE|j                  d«      xs d}||v rŒ_|j                  |«       | j                  ||j                  d	«      |j                  d
«      xs d«      }|r|j                  «       sŒ¸|dz  }|–— ŒÂ y ­w)Nr   r
   u{   [oirp] Brak APIFY_API_KEY i brak seed_urls â€” pomijam ÅºrÃ³dÅ‚o (szukajradcy.pl/search jest zablokowany przez robots.txt).u#   [oirp] Apify zwrÃ³ciÅ‚ %d rekordÃ³wÚtypeÚprofiler7   r$   r8   r9   )Úsetr   r   ÚaddrM   Úis_validr   rp   Úwarningrz   rq   ÚlenÚ
isinstanceÚdictrH   rB   )r   ÚyieldedÚseenr7   ÚleadÚitemsÚitems          r!   ÚfetchzOirpScraper.fetchÆ   sw  è ø€ ØˆÜ›ˆð �>Š>Ø—~‘~ò 
�Ø—:’: '¨T¯Z©ZÒ"7ÙØ˜$‘;ØØ—‘˜”Ø×.Ñ.¨sÓ3�Ù 4§=¡=¤?ØØ˜1‘�Ø“
ð
ð ð �|Š|Ü�K‰Kð Uô Vàà—‘Ó!ˆÜ�‰Ð6¼¸E»
ÔCàò 	ˆDØ�zŠz˜g¨¯©Ò3ÙÜ˜d¤DÔ)¨T¯X©X°fÓ-=ÀÒ-JØØ—(‘(˜5“/Ò' RˆCØ�d‰{ØØ�H‰H�SŒMØ×'Ñ'¨¨T¯X©X°gÓ->ÀÇÁÈÓ@PÒ@VÐTVÓWˆDÙ˜tŸ}™}œØØ�q‰LˆGØ‹Jñ	ùs   ‚F"F$)NNNNNN)r   ú
int | Noner   ú
str | Noner   r‹   r   zlist[str] | Noner   rŒ   r   rŒ   )r7   Ústrr8   rŒ   r9   r�   ÚreturnúLead | None)r7   r�   rŽ   r�   )rŽ   r�   )rŽ   r„   )rŽ   z
list[dict])rŽ   zIterator[Lead])Ú__name__Ú
__module__Ú__qualname__r'   r   rB   rM   rR   rg   rz   rŠ   Ú__classcell__)r    s   @r!   r   r   K   sz   ø„ Ø€Dð !Ø Ø $Ø&*Ø Ø"ð5àð5ð ð5ð ð	5ð
 $ð5ð ð5ð õ5ó$(
óT	6ó,ó
ó$÷6)r"   r   )Ú__doc__Ú
__future__r   Úloggingr3   Útypingr   rr   Úbs4r   r$   r   Únotifierr   r	   Úbaser   r   Ú	getLoggerr�   rp   rc   rb   ÚDEFAULT_QUERYrn   rd   r   © r"   r!   ú<module>rž      sj   ðñõ" #ã Û 	Ý ã Ý å ß =ß %à€g×Ñ˜Ó!€à€Øˆv�WÐ€
Ø €à'€
ð€ô@d�-õ dr"   