Jak pobrać dane podmiotu gospodarczego z bazy GUS?

0

Próbuję pobrać dane podmiotu z bazy GUS na podstawie numeru NIP.

Przy pomocy WSDL Importer próbowałem zbudować interfejs do webserwisu i interfejs się tworzy, ale nie działa jak tego oczekuję (sypie błędami) , więc postanowiłem zejść poziom niżej i wykorzystać wprost klasę THTTPReqResp tak jak w poniższej, testowej funkcji:

function test: string;
var
  lHttpReqResp: THTTPReqResp;
  lSoapEnvelope: string;
  lMemStream: TMemoryStream;
begin
  result := 'OK';
  lHttpReqResp := THTTPReqResp.Create(nil);
  lMemStream := TMemoryStream.Create;
  try
    lSoapEnvelope := //
      ' <?xml version="1.0" encoding="UTF-8"?> ' + //
      '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07"> ' + //
      '  <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"> ' + //
      '    <wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To> ' + //
      '    <wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj</wsa:Action> ' + //
      '  </soap:Header> ' + //
      '  <soap:Body> ' + //
      '    <ns:Zaloguj> ' + //
      '      <ns:pKluczUzytkownika>abcde12345abcde12345</ns:pKluczUzytkownika> ' + //
      '    </ns:Zaloguj> ' + //
      '  </soap:Body> ' + //
      '</soap:Envelope> ';
    try
      lHttpReqResp.UseUTF8InHeader := True;
      lHttpReqResp.Connect(False);
      lHttpReqResp.URL := 'https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc';
      lHttpReqResp.InvokeOptions := [soNoValueForEmptySOAPAction];
      lHttpReqResp.Execute(lSoapEnvelope, lMemStream);
    except
      on e: Exception do
        result := e.Message;
    end;
  finally
    lMemStream.Free;
    lHttpReqResp.Free;
  end;
end; 

Rezultatem funkcji jest string ''OK" albo string z opisem błędu (e.message).
Niestety, w rezultacie dostaję takie coś:

Cannot process the message because the content type 'text/xml; charset="utf-8"' was not the expected type 'multipart/related; type="application/xop+xml"'. (415) - 'https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc'
0

Wydaje mi się, że error nie mógł być lepszy - poszukaj jak w THTTPReqResp zmienia się content-type na ten co chce serwer i zobacz czy pójdzie

0

@krwq
szukam cały dzień ale bez rezultatu
webserwisy nie są moją mocną stroną

0

@grzegorz_so, ja nie uzywalem Delphi od jakis 7 lat, nigdy nie robilem w nim webserwisu ani nie uzywalem THTTPReqResp i pierwszy wynik na googlu mi wyswietlil jak to zrobic.

Ustawiasz event: OnBeforePost na tak jak napisali w tym poscie:
https://stackoverflow.com/questions/13345540/how-to-add-overwrite-a-http-header-using-thttpreqresp
tylko zmien content-type na ten co masz napisane w errorze

0

@krwq:
Próbowałem to zanim wrzuciłem temat na forum
Teraz już nie pamiętam co było nie tak, być może miałem wtedy jakiś inny błąd, sprawdzę to ponownie

4

W załączniku masz gotowy wygenerowany moduł z WSDLa (generowałem w jakimś nowszym Delphi, XE7) oraz klasę do ogarnięcia tego. Używa się to tak (ten x to tylko żebyś wiedział co jest co :)):

procedure AddressFromNIP(const NIP: string);
const
  UserKey = 'klucz użytkownika';
var
  wyszukiwarka: TWyszukiwarkaRegon;
  node: IXMLNode;
begin
  try
    wyszukiwarka := TWyszukiwarkaRegon.Create;
    if wyszukiwarka.Login(UserKey) then
    begin
      if wyszukiwarka.InfoByNIP(NIP) then
      begin
        node := wyszukiwarka.SearchResult.ChildNodes.FindNode('root').ChildNodes.FindNode('dane');
        x.NIP := NIP;
        x.Name := node.ChildNodes.FindNode('Nazwa').Text;
        x.Street := node.ChildNodes.FindNode('Ulica').Text;
        x.Number := '';
        x.PostalCode := node.ChildNodes.FindNode('KodPocztowy').Text;
        x.City := node.ChildNodes.FindNode('Miejscowosc').Text;
        x.Country := '';

        node := node.ChildNodes.FindNode('Regon');
        if (node <> nil) and (node.text <> '') then
        begin
          if wyszukiwarka.FullReport(node.Text) then
          begin
            node := wyszukiwarka.SearchResult.ChildNodes.FindNode('root').ChildNodes.FindNode('dane');
            if (node <> nil) and node.HasChildNodes  then
            begin
              x.NIP := NIP;
              x.Name := node.ChildNodes.FindNode('praw_nazwa').Text;
              x.Street := node.ChildNodes.FindNode('praw_adSiedzUlica_Nazwa').Text;
              x.Number := node.ChildNodes.FindNode('praw_adSiedzNumerNieruchomosci').Text;
              x.PostalCode := node.ChildNodes.FindNode('praw_adSiedzKodPocztowy').Text;
              x.City := node.ChildNodes.FindNode('praw_adSiedzMiejscowosc_Nazwa').Text;
              x.Country := node.ChildNodes.FindNode('praw_adSiedzKraj_Nazwa').Text;
            end;
          end
          else
            x.ErrorMsg := wyszukiwarka.ErrorMessage;
        end;
      end
      else
        x.ErrorMsg := wyszukiwarka.ErrorMessage;
      wyszukiwarka.Logout;
    end;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;
3

A bez modułu taka zabawa na piechotę.

type
  TGUSActions = (gaZaloguj, gaDanePobierzPelnyRaport); //itd
//ciach
procedure TForm2.BeforeRRPost(const HTTPReqResp: THTTPReqResp; Data: Pointer);
const
  sActions: array [Low(TGUSActions)..High(TGUSActions)] of String = (
    'action="http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj"',
    'action="http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DanePobierzPelnyRaport"'
    ); //itd
  cContentHeader = 'Content-Type: application/soap+xml;charset=UTF-8;';
  cSidHeader = 'sid: ';
begin
  HttpAddRequestHeaders(Data, PChar(cContentHeader + sActions[fGUSaction]), Length(cContentHeader + sActions[fGUSaction]), HTTP_ADDREQ_FLAG_REPLACE);
  if Length(fSessionId) > 0 then
    HttpAddRequestHeaders(Data, PChar(cSidHeader + fSessionId), Length(cSidHeader + fSessionId), HTTP_ADDREQ_FLAG_ADD);
end;

function TForm2.CreateGUSFrame(Action, Body: string): string;
begin
  result:=
    '<?xml version="1.0" encoding="UTF-8"?> ' +
    '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07"> ' +
    '  <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"> ' +
    '    <wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To> ' +
    '    <wsa:Action>' + Action + '</wsa:Action> ' +
    '  </soap:Header> ' +
    '  <soap:Body> ' +
    Body +
    '  </soap:Body> ' +
    '</soap:Envelope>';
end;

function ExtractData(sBegin, sEnd, sData: string): string;
var
  iStartPos, iEndPos: integer;
begin
  Result := '';
  iStartPos := Pos(sBegin, sData) + Length(sBegin);
  iEndPos := PosEx(sEnd, sData, iStartPos);
  if (iStartPos > Length(sBegin)) and (iEndPos > iStartPos) then Result := Copy(sData, iStartPos, iEndPos - iStartPos);
end;

function TForm2.Test: string;
var
  lHttpReqResp: THTTPReqResp;
  lSoapEnvelope: string;
  lStrStream: TStringStream;
  sBody: string;
begin
  result := 'OK';
  fSessionId:= '';
  lHttpReqResp := THTTPReqResp.Create(nil);
  lStrStream := TStringStream.Create;
  try
    sBody:=
      '    <ns:Zaloguj> ' +
      '      <ns:pKluczUzytkownika>abcde12345abcde12345</ns:pKluczUzytkownika> ' +
      '    </ns:Zaloguj> ';

    lSoapEnvelope:= CreateGUSFrame('http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj', sBody);

    try
      lHttpReqResp.OnBeforePost:= BeforeRRPost;
      lHttpReqResp.UseUTF8InHeader := True;
      lHttpReqResp.Connect(False);
      lHttpReqResp.URL := 'https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc';
      lHttpReqResp.InvokeOptions := [soNoValueForEmptySOAPAction];

      fGUSaction:= gaZaloguj;
      lHttpReqResp.Execute(lSoapEnvelope, lStrStream);

      lStrStream.Position:= 0;

      //tu wyciągnać ZalogujResult to chyba ma być SessionId
      fSessionId:= ExtractData('<ZalogujResult>', '</ZalogujResult>', lStrStream.ReadString(lStrStream.Size));

      lStrStream.Clear;


      sBody:=
        '    <ns:DanePobierzPelnyRaport> ' +
        '    <ns:pRegon>00033150100000</ns:pRegon> ' +
        '    <ns:pNazwaRaportu>PublDaneRaportPrawna</ns:pNazwaRaportu> ' +
        '    </ns:DanePobierzPelnyRaport>';

      lSoapEnvelope:= CreateGUSFrame('http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DanePobierzPelnyRaport', sBody);

      fGUSaction:= gaDanePobierzPelnyRaport;
      lHttpReqResp.Execute(lSoapEnvelope, lStrStream);

      lStrStream.Position:= 0;

      Memo1.Text:= lStrStream.ReadString(lStrStream.Size);
    except
      on e: Exception do
        result := e.Message;
    end;
  finally
    lStrStream.Free;
    lHttpReqResp.Free;
  end;
end;
0

@abrakadaber: , @kAzek
dzięki, muszę to wypróbować

0

@kAzek:
wielkie dzięki, Twoje rozwiązanie działa :))

0

@abrakadaber:
Dzięki za chęć pomocy ale moje Delphi jest trochę za stare. Gdyby nie było tak stare to sam bym w ten sposób rozwiązał problem, bo od tego własnie zacząłem :)

0

znaczy co kod, który Ci podałem nie działa? Przecież sam kod się niczym nie różni - różnica była w narzędziu, którego używa delphi do wygenerowania kodu z WSDLa - te ze starszych wersji nie dają rady. Ale gotowy kod nawet na D7 powinien zadziałać.

0

@abrakadaber:
Jest różnica w kodzie , w moim Delphi (D2010) klasa TInvokableClassRegistry nie posiada metody RegisterMethodInfo, tym samym kod się nawet nie skompiluje

0
abrakadaber napisał(a):

W załączniku masz gotowy wygenerowany moduł z WSDLa (generowałem w jakimś nowszym Delphi, XE7) oraz klasę do ogarnięcia tego. Używa się to tak (ten x to tylko żebyś wiedział co jest co :)):

procedure AddressFromNIP(const NIP: string);
const
  UserKey = 'klucz użytkownika';
var
  wyszukiwarka: TWyszukiwarkaRegon;
  node: IXMLNode;
begin
  try
    wyszukiwarka := TWyszukiwarkaRegon.Create;
    if wyszukiwarka.Login(UserKey) then
    begin
      if wyszukiwarka.InfoByNIP(NIP) then
      begin
        node := wyszukiwarka.SearchResult.ChildNodes.FindNode('root').ChildNodes.FindNode('dane');
        x.NIP := NIP;
        x.Name := node.ChildNodes.FindNode('Nazwa').Text;
        x.Street := node.ChildNodes.FindNode('Ulica').Text;
        x.Number := '';
        x.PostalCode := node.ChildNodes.FindNode('KodPocztowy').Text;
        x.City := node.ChildNodes.FindNode('Miejscowosc').Text;
        x.Country := '';

        node := node.ChildNodes.FindNode('Regon');
        if (node <> nil) and (node.text <> '') then
        begin
          if wyszukiwarka.FullReport(node.Text) then
          begin
            node := wyszukiwarka.SearchResult.ChildNodes.FindNode('root').ChildNodes.FindNode('dane');
            if (node <> nil) and node.HasChildNodes  then
            begin
              x.NIP := NIP;
              x.Name := node.ChildNodes.FindNode('praw_nazwa').Text;
              x.Street := node.ChildNodes.FindNode('praw_adSiedzUlica_Nazwa').Text;
              x.Number := node.ChildNodes.FindNode('praw_adSiedzNumerNieruchomosci').Text;
              x.PostalCode := node.ChildNodes.FindNode('praw_adSiedzKodPocztowy').Text;
              x.City := node.ChildNodes.FindNode('praw_adSiedzMiejscowosc_Nazwa').Text;
              x.Country := node.ChildNodes.FindNode('praw_adSiedzKraj_Nazwa').Text;
            end;
          end
          else
            x.ErrorMsg := wyszukiwarka.ErrorMessage;
        end;
      end
      else
        x.ErrorMsg := wyszukiwarka.ErrorMessage;
      wyszukiwarka.Logout;
    end;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;

Witam,
Mam takie pytanie - w jaki sposób można odczytać numer budynku? W podanym kodzie jest x.Number := ''; czy numer jest w polu z ulicą?
pozdrawiam

0

numer jest w pełnym raporcie FullReport, linia x.Number := node.ChildNodes.FindNode('praw_adSiedzNumerNieruchomosci').Text; ale kto by tam gotowce do końca czytał...

3

Odkopię trochę stary wątek dla potomnych.
W innym temacie szukałem "najlepszego" rozwiązania na pobranie danych firmy na podstawie nip-u. Tak jak myślałem, istnieją opinie że baza GUS-u jest trochę lepsza od bazy CEIDG.

Chcąc z niej skorzystać można samemu pokombinować lub użyć kilku gotowych rozwiązań dostępnych chociażby tutaj na forum.
Najciekawsze wydaje mi się rozwiązanie kolegi @abrakadaber Jak pobrać dane podmiotu gospodarczego z bazy GUS? Niestety pisał je dość dawno temu, gdy chyba jeszcze nie było wersji BIR1.1 tylko stara wersja BIR1.
Niby nie ma dużo różnic miedzy tymi wersjami ale jednak jest coś co jest ważne.
Przechodząc do szczegółów: interesujące dane pobiera się jako raport powiedzmy: zwykły albo pełny.
Problemem wersji BIR1, jest to że w raporcie "zwykłym" brakuje numeru nieruchomości i numeru lokalu! Jest to dość irytujące.

W wersji BIR1.1 te dane zostały już dołożone.
Oczywiście, zawsze można użyć raportu pełnego, ale tam dane są rozbite na osoby fizyczne, rolnicy, spółki, jednostki administracji. Jest to dość dużo do kodowania a szczerze, szkoda na to trochę czasu oczekując prostej funkcji do pobierania danych.

Na szczęście podłączenie się pod nową wersję BIR jest dziecinnie proste (szczerze, to już jesteśmy podłączeni, tylko używamy złego wywołania), po pierwsze, klucz który otrzymujemy z gus-u (wyjątkowo łatwo go zdobyć) działa z nową wersją bez problemu, po drugie, w kodzie kolegi @abrakadaber w pliku WyszukiwarkaRegon.pas wystarczy odszukać funkcję InfoByNIP:

function TWyszukiwarkaRegon.InfoByNIP(const NIP: string): Boolean;
var
  body: string;
begin
  body := '';
  body := body + '<ns:pParametryWyszukiwania>'#13#10;
  body := body + '  <dat:Nip>' + NIP + '</dat:Nip>'#13#10;
  body := body + '</ns:pParametryWyszukiwania>'#13#10;
  FSearchResult := XMLFromResponse(GetResponse('DaneSzukaj', body));
  Result := FSearchResult <> nil;
  if not Result then
    GetErrorMessage;
end;

I zmienić linię:

FSearchResult := XMLFromResponse(GetResponse('DaneSzukaj', body));

na

FSearchResult := XMLFromResponse(GetResponse('DaneSzukajPodmioty', body));

Później już spokojnie można użyć odpowiednich nodów w kodzie który kolega podrzucił:

node := wyszukiwarka.SearchResult.ChildNodes.FindNode('root').ChildNodes.FindNode('dane');
        x.NIP := NIP;
        x.Name := node.ChildNodes.FindNode('Nazwa').Text;
        x.Street := node.ChildNodes.FindNode('Ulica').Text;
        x.Number := node.ChildNodes.FindNode('NrNieruchomosci').Text; // już działa
        x.Nrlokalu := node.ChildNodes.FindNode('NrLokalu').Text; // i to też działa
        x.PostalCode := node.ChildNodes.FindNode('KodPocztowy').Text;
        x.City := node.ChildNodes.FindNode('Miejscowosc').Text;
        x.Country := '';

I to wszystko. Dzięki @abrakadaber

0

Zauważyłem ten temat dlatego zamieszczam tutaj pytania gdyż jest związane z tym tematem. Poniżej wysyłam dane jakie wysyłam - wyglądają na poprawne a otrzymuje HTTP 400 Bad Request.

Czy ktoś może rzucić fachowym okiem co jest źle? Robiłem to na podstawie dokumentacji z BIR

POST /wsBIR/UslugaBIRzewnPubl.svc HTTP/1.1
Accept: */*
Accept-Encoding: gzip,deflate
User-Agent: Borland SOAP 1.2
Content-Length: 645
Content-Type: application/soap+xml;charset=UTF-8;action="http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneSzukajPodmioty"
Cache-Control: no-cache
Connection: Keep-Alive
POST https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc HTTP/1.1
Host: wyszukiwarkaregon.stat.gov.pl


<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07" xmlns:dat="http://CIS/BIR/PUBL/2014/07/DataContract">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>
<wsa:Action>https://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneSzukajPodmioty</wsa:Action>
</soap:Header>
<soap:Body>
<ns:DaneSzukajPodmioty>
<ns:pParametryWyszukiwania>
<dat:Nip>9991119911</dat:Nip>
</ns:pParametryWyszukiwania>
</ns:DaneSzukajPodmioty>
</soap:Body>
</soap:Envelope>

1

Masz 2x POST

POST /wsBIR/UslugaBIRzewnPubl.svc HTTP/1.1
POST https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc HTTP/1.1

1 użytkowników online, w tym zalogowanych: 0, gości: 1