أتمتة الحصول على معلومات من USRLE باستخدام Freepascal



في عملي (القانوني) ، أنا على استعداد لأتمتة كل شيء لا يصلح إلا لهذا. ولكن حتى ظهور الروبوتات التي تضخها الشبكات العصبية من اليوتوبيا الألمانية جيرف لم تظهر ولم تأخذ جميع الأعمال من المحامين العاديين ، سيظل الروتين رفيقنا الرئيسي لفترة طويلة. إن أتمتة هذا الروتين هو شيء كنت أفعله بشكل دوري على مدى السنوات الماضية ، سواء كان ذلك في العديد من الجداول في excel مع مجموعة من الصيغ التي تسمح لك بطباعة مئات من نفس النوع من المستندات البريدية بسرعة أو بشكل جيد ، التقارير التي يتم إنشاؤها تلقائيًا. ولكن هناك أشياء لا يمكنك القيام بها باستخدام الصيغ والبدائل البسيطة. هذا هو المكان الذي تأتي فيه البرمجة إلى الإنقاذ ، التي كنت مغرمًا بها منذ الطفولة ، وقد حدث أن بدأت مع دلفي. الآن أصبح الأمر أسهل بالنسبة لي من C # أو الثعبان ، الذي بدأت أتعلمه مؤخرًا ، للقيام بسرعة بنوع من المشاريع في بيئة Lazarus باستخدام freepascal. ونعم ، أعتقد بجدية أن قدرات هذه البيئة أكثر من كافية. لذلك ، أتممت USRLE ، كما توقعت ، يجب القيام به باستخدام باسكال.

محامي شركة استشارية يدير أعمال العشرات من الكيانات القانونية ، ومحامي مؤسسي يعتمد على الخبز المجاني ، وأي محام آخر يواجه ضمان أنشطة المنظمات - كلهم ​​يعرفون كيف أن العشرات والمئات من الأسماء المختلفة ، وأرقام TIN ، وأرقام PSRN تختلط في رأسك ، وكيف من السهل نسيان من هو المدير ، وعندما تكون فترة التجديد مناسبة ، هل هناك أي مشاكل في الأسهم في شركة ذات مسؤولية محدودة ودفع رأس مالها المستأجر. حسنًا ، إن الحاجة إلى إنشاء نوع من المستندات بسرعة ، والتي تتضمن العديد من التفاصيل المتغيرة باستمرار ، تنطوي على أخطاء وأخطاء مطبعية دورية. لأتمتة هذه العمليات فقط ، كنت بحاجة إلى حل قاعدة بيانات يسمح لي بإنشاء مستندات باستخدام القوالب ، والحفاظ على سجلات مختلفة ، وتتبع التغييرات وعدم تفويت أي مواعيد نهائية. حسنًا ، أحد تبسيطات الحياة الضرورية هو الاستلام السريع لملف جديد يحتوي على معلومات من USRLE من موقع خدمة الضرائب الفيدرالية . بالطبع ، لا أحد يقول أن استخدام الموقع مباشرة طويل وصعب ، ولكن اتفق على أن النقر على زر واحد دون مغادرة التطبيق هو أكثر متعة ، ويمكنك القيام بذلك دون كسر المكالمة الهاتفية (أو فنجان قهوة).

لذا ، كبداية سنقرر ما نريد الحصول عليه. يتيح لك الموقع البحث في السجل الرسمي لـ USRLE عن رقم OGRN أو TIN فريد وإعطاء نتيجة واحدة ذات صلة في شكل معلومات موجزة عن الشخص ورابط لتنزيل ملف pdf مع مقتطف. أيضا ، قد يكون البحث غير واضح بالاسم مع مرشح إضافي حسب المنطقة (موضوع الاتحاد الروسي). وفي هذه الحالة ، يصدر الموقع جدولًا مع جميع الأشخاص المناسبين وبنفس مجموعة البيانات ، بما في ذلك روابط إلى pdf.

لذلك ، في حالة معينة ، يجب أن ترجع الوظيفة الجاهزة ملف pdf في شكل ملف (أو ، أفضل ، تيار) ، مع وجود OGRN أو TIN عند الإدخال. ولكن من أجل إضفاء الطابع العالمي وإمكانية التوسع بشكل أكبر ، لن نتجاهل جميع ميزات الموقع ونقوم أيضًا بوظيفة بحث غامضة مع إرجاع مجموعة من البيانات التي تم العثور عليها باسم المنظمة ، مع مراعاة عامل التصفية حسب المنطقة أو بدونها. دعونا نحاول وصف واجهات هذه الوظائف:

IEGRULstreamer = interface procedure GetExtractByOGRN(OGRN: string; ; isLegal: boolean; var Extract: TStream); procedure GetLegalsListByName(Name, Region: string; ; var LegalsList: TCollection); end; 

من أجل فهم ما هي المعلمة الغامضة X والمجموعة التي ستعود الوظيفة الثانية إليها ، سنرى كيف ينفذ الموقع الطلب.

1. يحتوي الموقع على نموذج يحتوي على حقول إدخال لمعرفات البحث والتدقيق على كلمة التحقق:



2. يتم إنشاء اختبار CAPTCHA باستخدام حقل مخفي تم إنشاؤه مسبقًا باسم captchaToken ، والذي يستخدم برنامج Java النصي لإنشاء صورة اختبار CAPTCHA لهذا الرمز المميز.

3. بعد النقر فوق الزر "بحث" ، يتم إرسال طلب POST إلى الخادم ، في نتائج المعالجة التي يتم إرجاع JSON بها مجموعة من الكائنات. تستخدم استجابة JSON هذه نص Java آخر لملء الجدول الذي نراه في نتائج البحث.

لذا ، فإن أول مشكلة هي التحقق من اختبار captcha. لكي لا نثقل كاهل طرقنا في التفاعل مع الموقع بوظائف زائدة ، سنتخذ إجراءات لمعالجة اختبار CAPTCHA كوظيفة منفصلة. وفي X ، سيكون لدينا معلمة لأسلوب رد الاتصال ، والتي تحتوي على صورة captcha عند الإدخال وسلسلة مع captcha معترف بها عند الإخراج:

 TCapthcaRecognizeFunc = function(Captha: TStream): string of object; ... procedure GetExtractByOGRN(OGRN: string; CaptchaFunc: TCapthcaRecognizeFunc; isLegal: boolean; var Extract: TStream); 

يمكن أن تقوم وظيفة معالجة CAPTCHA بذلك كما تشاء: اسمح للمستخدم بإدخالها يدويًا ، وإرسال الصورة إلى خادم مدفوع للتعرف التلقائي ، والتعرف عليها بشكل مستقل باستخدام الدراية الفريدة للخوارزمية. من أجل بساطة الصورة ، وبما أنه في حالتي لا يتوقع تدفق captcha على نطاق صناعي ، فإننا نختار الخيار الأول:

 function TForm1.RecognizeFunc(captcha: TStream): string; begin CaptchaImg.Picture.LoadFromStream(captcha); Result := InputBox('','    ', ''); end; 

السؤال الثاني هو محتويات استجابة JSON للخادم. فيما يلي مثال على ما يأتي فيه:

استجابة بتنسيق JSON
 { "query": {"captcha":"382915", "ogrninnfl":null, "fam":null, "nam":null, "otch":null, "region":null, "ogrninnul":null, "namul":"", "regionul":"73", "kind":"ul", "ul":true, "searchByOgrn":false, "nameEq":false, "searchByOgrnip":true}, "rows": [ {"T":"ED346E713D4A1AC851F9B589C6D2AECD1D809D5B6B5D1B98E697B6E0FD873E137B828AC59A60D159BB2894F11D00AB5639E2ACEE4E2ED5B7AC7A6EFE28FD987BC288B93C4D3D3EC1008DA0F128BA7E5E", "INN":"7325001144", "NAME":"  ", "OGRN":"1027301175110", "ADRESTEXT":"432017,  ,  ,  , 1", "CNT":"4", "DTREG":"03.12.2002", "KPP":"732501001"}, {"T":"2ECB284C7682E5F1D1129AA3074FABB4B74BB28EA426AF79C091CEDEA0D9E391CA26FF405A7C9742466E19C78FBE5A59BDCBCD21268FFD8AFD3A8509CCA84541", "INN":"7303007375", "NAME":"      \"   \"", "OGRN":"1027301173283", "ADRESTEXT":"432063,  ,  ,   , 7", "CNT":"4", "DTREG":"27.11.2002", "KPP":"732501001", "DTEND":"01.09.2010"}, ] } 


كما ترى ، ترجع النتيجة كائن استعلام يحتوي على معلمات البحث الأولية (بحيث تظل في حقول النموذج لإعادة استخدامها) ومجموعة من الصفوف. تم دمج الرابط إلى ملف pdf مع نص جافا باستخدام التعبير:
  "https://egrul.nalog.ru/download/" 
والقيمة الرئيسية "T" للكائن. عمر ملف pdf الذي تم إنشاؤه بضع دقائق.

الصعبتان الرئيسيتان اللتان واجهتهما أثناء إنشاء طلب http هما قيم الرؤوس الصحيحة والجمع بين السلسلة ومعلمات طلب POST. لكن التحليل البسيط للصفحة باستخدام أدوات المتصفح المدمجة (يُسمى Chrome بالضغط على F12) أعطى كل ما تحتاجه. في ما يلي مثال على الرؤوس التي يقدم الخادم من خلالها الإجابة الصحيحة بدلاً من 400 طلب غير صحيح:

 POST / HTTP/1.1 Host: egrul.nalog.ru Connection: keep-alive Accept: application/json, text/javascript, */*; q=0.01 Origin: https://egrul.nalog.ru X-Requested-With: XMLHttpRequest User-Agent: Chrome/67.0.3396.99 Safari/537.36 Content-Type: application/x-www-form-urlencoded Referer: https://egrul.nalog.ru/ Accept-Encoding: gzip, deflate, br Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7 

وهنا الخط مع المعلمات:

 kind=ul&srchUl=name&ogrninnul=7716819629&namul=%D0%BF%D1%80%D0%B0%D0%B2% D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D1%82%D0%B2%D0%BE&regionul=73 &srchFl=ogrn&ogrninnfl=&fam=&nam=&otch=&region=&captcha=449023&captchaToken=DAEDA 7504CACAC82CF09E08319B68DF5F9BD62B2F44D33DD679DDE55B5CF58B17FEC84E78CEEB9639 84D2B2BD8C3AA15 

مسلحين بهذه البيانات الأولية ، نمضي في تنفيذ المهمة. سأستخدم المكتبات التالية من أجل Freepascal:

Synapse هي مكتبة مريحة للغاية مع وظيفة أبسط (للاستخدام) لإرسال طلبات http إلى الخادم ، كما أنها تعمل مع SSL ، ولكن هذا يتطلب وجود مكتبات openSSL في مجلد المشروع أو النظام ، بالإضافة إلى اتصال وحدة إضافية. يكفي توصيل وحدات المكتبة التالية بمشروعنا: httpsend، ssl_openssl، synautil.

مكتبة fcl-json المدمجة - الوحدات الضرورية: fpjson و fpjsonrtti - لتحقيق أقصى راحة لمعالجة العناصر التي تم إرجاعها إلى JSON.

وحدات منفصلة للمكتبة المدمجة fcl-xml - بالنسبة لبعض الوظائف ، ستحتاج إلى العمل مع أجزاء من HTML ككائنات DOM ، لذلك سنقوم بتوصيل وحدات SAX_HTML و DOM_HTML و DOM.

دعونا نصف أنواع وأنواع الأشياء التي تحولت في النهاية:

 TEGRULItem = class(TCollectionItem) private fT, fINN, fNAME, fOGRN, fADRESTEXT, fCNT, fDTREG, fDTEND, fKPP: string; public function GetPdfLink: string; published property T: string read fT write fT; property INN: string read fINN write fINN; property NAME: string read fNAME write fNAME; property OGRN: string read fOGRN write fOGRN; property ADRESTEXT: string read fADRESTEXT write fADRESTEXT; property CNT: string read fCNT write fCNT; property DTREG: string read fDTREG write fDTREG; property DTEND: string read fDTEND write fDTEND; property KPP: string read fKPP write fKPP; end; 

في هذه الفئة ، سنحزم الكائنات التي سيتم إرجاعها في صفيف الصفوف في استجابة JSON للخادم. سنقرأها باستخدام JSONToCollection ، ولكن من أجل هذا ، نحتاج إلى جعل كل كائن عنصرًا في المجموعة ونعلن عن كل الخصائص ذات الصلة كما تم نشرها. تعمل وظائف RTTI في freepascal (وكذلك في دلفي) على الوصول إلى أسماء الخصائص فقط عندما يتم الإعلان عنها في هذا النطاق. ووظيفة JSONToCollection من وحدة fpjsonrtti هي مجرد دالة RTTI تقارن أسماء المفاتيح من كائن JSON مع أسماء خصائص الفئة.

هناك أيضًا وظيفة GetPdfLink في واجهة الفصل ، والتي تقوم بإرجاع رابط لتنزيل ملف pdf يحتوي على معلومات من USRLE من خلال ربط عنوان الويب وقيمة الخاصية "T".


سيكون الفصل الرئيسي الذي يقوم بتنفيذ الواجهة المذكورة أعلاه على النحو التالي:

  TEGRULStreamer = class(TInterfacedObject, IEGRULStreamer) private HTTPSender: THTTPSend; Doc: THTMLDocument; Inputs: TDOMNodeList; captchaURL, captchaToken, captcha, Params: string; function GetCaptchaToken: string; function GetLegalsList: TCollection; procedure PrepareHeaders; procedure ProcessCaptcha(CaptchaFunc: TCapthcaRecognizeFunc); public procedure GetExtractByOGRN(OGRN: string; CaptchaFunc: TCapthcaRecognizeFunc; isLegal: boolean; var Extract: TStream); procedure GetLegalsListByName(Name, Region: string; CaptchaFunc: TCapthcaRecognizeFunc; var LegalsList: TCollection); destructor Destroy; override; end; 


كما ترى ، بالإضافة إلى تنفيذ الوظيفتين الرئيسيتين للواجهة ، سيتم إخفاء جميع الخصائص والأساليب الأخرى للفئة وهي مطلوبة فقط للتنفيذ الداخلي. بشكل عام ، يمكن تضمينها في الطرق الرئيسية ، ولكننا قد مررنا بالفعل بالدروس حول تكرار التعليمات البرمجية والتصور وإعادة الهيكلة بشكل عام.

بالنظر إلى تغليف الإجراءات التحضيرية ، ستختلف الطرق الرئيسية بشكل عام فقط عن طريق تشكيل سلسلة من معلمات طلب http ونوع البيانات التي تم إرجاعها.

كود الطريقة TEGRULStreamer.GetExtractByOGRN
 procedure TEGRULStreamer.GetExtractByOGRN(OGRN: string; CaptchaFunc: TCapthcaRecognizeFunc; isLegal: boolean; var Extract: TStream); begin ProcessCaptcha(CaptchaFunc); if isLegal then Params := 'kind=ul' else Params := 'kind=fl'; Params += '&srchUl=ogrn&srchFl=ogrn&ogrninnul='; if isLegal then Params += OGRN; Params += '&namul=&regionul=&ogrninnfl='; if not isLegal then Params += OGRN; Params += '&fam=&nam=&otch=&region&captcha=' + captcha + '&captchaToken=' + captchaToken; WriteStrToStream(HTTPSender.Document, Params); if not HTTPSender.HTTPMethod('POST', EGRUL_URL) then raise Exception.Create('   '); HTTPSender.Headers.Clear; if HTTPSender.HTTPMethod('GET', TEGRULItem(GetLegalsList.Items[0]).GetPdfLink) then Extract := HTTPSender.Document else Extract := nil; 


هنا ، كما نرى ، تستخدم الطريقة أيضًا المعلمة المنطقية isLegal ، وإذا لم يتم تعيينها على true ، فإن البحث يمر عبر قاعدة بيانات رواد الأعمال بدلاً من الكيانات القانونية.

كود الطريقة TEGRULStreamer.GetLegalsListByName
 procedure TEGRULStreamer.GetLegalsListByName(Name, Region: string; CaptchaFunc: TCapthcaRecognizeFunc; var LegalsList: TCollection); begin ProcessCaptcha(CaptchaFunc); Params := 'kind=ul&srchUl=name&srchFl=ogrn&ogrninnul=&namul='; Params += Name + '&regionul=' + Region + '&ogrninnfl=&fam=&nam=&otch=&region'; Params += '&captcha=' + captcha + '&captchaToken=' + captchaToken; WriteStrToStream(HTTPSender.Document, Params); if not HTTPSender.HTTPMethod('POST', EGRUL_URL) then raise Exception.Create('   '); LegalsList := GetLegalsList; end; 


دور طرق المنفعة على النحو التالي:

ProcessCaptcha - يقوم بتنزيل صفحة html الأولية من خدمة الضرائب الفيدرالية ، ويبحث عن رمز captcha المميز ، وينزل صورة تم إنشاؤها بواسطة هذا الرمز المميز ، ويعيد توجيهها إلى طريقة رد الاتصال للتعرف على captcha. في النهاية ، تقوم الطريقة أيضًا بتعيين الرؤوس الصحيحة لطلب POST اللاحق.

GetCaptchaToken - يتم تحميل جميع حقول الإدخال من الصفحة إلى بنية DOM ، ويبحث عن حقل مخفي مع معرف المعرف ويعيد قيمته.

GetLegalsList - باستخدام دالة RTTI ، تقوم JSONToCollection بإرجاع مجموعة من الكائنات من النوع TEGRULItem الموضح أعلاه.

GetPdfLink - للبحث بواسطة OGRN أو TIN ، في الحالة الصحيحة ، سيتم إرجاع نتيجة واحدة فقط دائمًا ، لذلك في GetExtractByOGRN يتم استدعاء الوظيفة للعنصر الأول في المجموعة.

نظرًا لأن هذه هي تجربتي الأولى مع شبكة في Freepascal ، يسعدني جدًا أن كل شيء قد تحول تمامًا كما كنت أقصد. في نموذج عمل ، تم إنشاء المكتبة في أقل من يوم واحد (بفضل مستخدمي المنتدى من freepascal.ru ، الذين تحدثوا عن المشبك).

أرشيف مع اختبار للمكتبة الناتجة ورمزها هنا .

كما هو الحال دائمًا ، سأكون سعيدًا بأي نقد بناء على كل من المشروع والتنفيذ. أفهم أن هناك العديد من العوامل التي لا يزال من الممكن أخذها في الاعتبار: التأخير في الاستجابة لطلب http ، ونتيجة لذلك سيتم تجميد التطبيق ؛ استجابات http غير صحيحة والمواقف الأخرى.

في المستقبل ، أخطط لربط مكتبة عبر الإنترنت بقاعدة بيانات عناوين FIAS وإدراك القدرة على إنشاء قوالب التطبيقات المكتملة ، والتي يتم تحريرها بشكل عام في برنامج إعداد المستندات لتسجيل الدولة .


PS عذرا ، Sberbank ، لدور الأرنب التجريبي ومئات المرات تحميل مقتطف. كل ذلك باسم العلم بالطبع.

Source: https://habr.com/ru/post/ar419063/


All Articles