Changeset 47f4eaf
- Timestamp:
- 11/20/22 16:34:52 (2 years ago)
- Branches:
- master
- Parents:
- ffd50db
- Files:
-
- 87 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
phonelux-backend/pom.xml
rffd50db r47f4eaf 69 69 </dependency> 70 70 71 <dependency> 72 <groupId>org.springframework.boot</groupId> 73 <artifactId>spring-boot-starter-oauth2-client</artifactId> 74 </dependency> 75 71 76 </dependencies> 72 77 -
phonelux-backend/src/main/java/finki/it/phoneluxbackend/entities/User.java
rffd50db r47f4eaf 78 78 } 79 79 80 public User(String firstName, String lastName, String email, UserRole userRole) { 81 this.firstName = firstName; 82 this.lastName = lastName; 83 this.email = email; 84 this.userRole = userRole; 85 } 86 80 87 @Override 81 88 public Collection<? extends GrantedAuthority> getAuthorities() { -
phonelux-backend/src/main/java/finki/it/phoneluxbackend/security/configs/WebSecurityConfig.java
rffd50db r47f4eaf 5 5 import finki.it.phoneluxbackend.services.UserService; 6 6 import lombok.AllArgsConstructor; 7 import org.springframework.beans.factory.annotation.Autowired; 7 8 import org.springframework.context.annotation.Bean; 8 9 import org.springframework.context.annotation.Configuration; … … 17 18 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 18 19 19 import static org.springframework.http.HttpMethod.GET;20 21 20 @Configuration 22 21 @AllArgsConstructor … … 26 25 private final UserService userService; 27 26 private final BCryptPasswordEncoder bCryptPasswordEncoder; 28 29 27 @Override 30 28 protected void configure(HttpSecurity http) throws Exception { … … 47 45 .antMatchers("/admin/**") 48 46 .hasAnyAuthority("ADMIN","SUPERADMIN") 47 .and() 48 .authorizeRequests() 49 .antMatchers("/offerreport/**") 50 .hasAnyAuthority("USER", "ADMIN", "SUPERADMIN") 51 .and() 52 .authorizeRequests() 53 .antMatchers("/scrapperinfo/**") 54 .hasAnyAuthority("SUPERADMIN") 55 .and() 56 .authorizeRequests() 49 57 .anyRequest().permitAll(); 50 51 58 52 59 … … 55 62 56 63 } 64 57 65 58 66 @Override -
phonelux-backend/src/main/java/finki/it/phoneluxbackend/services/RegistrationService.java
rffd50db r47f4eaf 1 1 package finki.it.phoneluxbackend.services; 2 2 3 import com.fasterxml.jackson.core.JsonParser;4 import com.fasterxml.jackson.core.io.JsonStringEncoder;5 import com.fasterxml.jackson.databind.ObjectMapper;6 import com.fasterxml.jackson.databind.util.JSONPObject;7 3 import finki.it.phoneluxbackend.data.RegistrationRequest; 8 4 import finki.it.phoneluxbackend.data.UserRole; … … 12 8 import finki.it.phoneluxbackend.security.email.EmailValidator; 13 9 import lombok.AllArgsConstructor; 14 import org.apache.coyote.Response;15 import org.apache.tomcat.util.json.JSONParser;16 10 import org.springframework.http.HttpStatus; 17 11 import org.springframework.http.ResponseEntity; … … 20 14 21 15 import java.time.LocalDateTime; 22 import java.util.HashMap;23 16 24 17 @Service -
phonelux-backend/src/main/java/finki/it/phoneluxbackend/services/UserService.java
rffd50db r47f4eaf 41 41 } 42 42 43 44 43 45 public ResponseEntity<Object> signUpUser(User user) 44 46 { -
phonelux-frontend/package-lock.json
rffd50db r47f4eaf 21 21 "@testing-library/user-event": "^13.5.0", 22 22 "@tippyjs/react": "^4.2.6", 23 "antd": "^4.23.6", 23 24 "axios": "^0.27.2", 24 25 "jwt-decode": "^3.1.2", … … 47 48 "engines": { 48 49 "node": ">=6.0.0" 50 } 51 }, 52 "node_modules/@ant-design/colors": { 53 "version": "6.0.0", 54 "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", 55 "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", 56 "dependencies": { 57 "@ctrl/tinycolor": "^3.4.0" 58 } 59 }, 60 "node_modules/@ant-design/icons": { 61 "version": "4.7.0", 62 "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.7.0.tgz", 63 "integrity": "sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g==", 64 "dependencies": { 65 "@ant-design/colors": "^6.0.0", 66 "@ant-design/icons-svg": "^4.2.1", 67 "@babel/runtime": "^7.11.2", 68 "classnames": "^2.2.6", 69 "rc-util": "^5.9.4" 70 }, 71 "engines": { 72 "node": ">=8" 73 }, 74 "peerDependencies": { 75 "react": ">=16.0.0", 76 "react-dom": ">=16.0.0" 77 } 78 }, 79 "node_modules/@ant-design/icons-svg": { 80 "version": "4.2.1", 81 "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz", 82 "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" 83 }, 84 "node_modules/@ant-design/react-slick": { 85 "version": "0.29.2", 86 "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz", 87 "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==", 88 "dependencies": { 89 "@babel/runtime": "^7.10.4", 90 "classnames": "^2.2.5", 91 "json2mq": "^0.2.0", 92 "lodash": "^4.17.21", 93 "resize-observer-polyfill": "^1.5.1" 94 }, 95 "peerDependencies": { 96 "react": ">=16.9.0" 49 97 } 50 98 }, … … 2169 2217 } 2170 2218 }, 2219 "node_modules/@ctrl/tinycolor": { 2220 "version": "3.4.1", 2221 "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", 2222 "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==", 2223 "engines": { 2224 "node": ">=10" 2225 } 2226 }, 2171 2227 "node_modules/@emotion/babel-plugin": { 2172 2228 "version": "11.10.2", … … 5253 5309 } 5254 5310 }, 5311 "node_modules/antd": { 5312 "version": "4.23.6", 5313 "resolved": "https://registry.npmjs.org/antd/-/antd-4.23.6.tgz", 5314 "integrity": "sha512-AYH57cWBDe1ChtbnvG8i9dpKG4WnjE3AG0zIKpXByFNnxsr4saV6/19ihE8/ImSGpohN4E2zTXmo7R5/MyVRKQ==", 5315 "dependencies": { 5316 "@ant-design/colors": "^6.0.0", 5317 "@ant-design/icons": "^4.7.0", 5318 "@ant-design/react-slick": "~0.29.1", 5319 "@babel/runtime": "^7.18.3", 5320 "@ctrl/tinycolor": "^3.4.0", 5321 "classnames": "^2.2.6", 5322 "copy-to-clipboard": "^3.2.0", 5323 "lodash": "^4.17.21", 5324 "memoize-one": "^6.0.0", 5325 "moment": "^2.29.2", 5326 "rc-cascader": "~3.7.0", 5327 "rc-checkbox": "~2.3.0", 5328 "rc-collapse": "~3.3.0", 5329 "rc-dialog": "~8.9.0", 5330 "rc-drawer": "~5.1.0", 5331 "rc-dropdown": "~4.0.0", 5332 "rc-field-form": "~1.27.0", 5333 "rc-image": "~5.7.0", 5334 "rc-input": "~0.1.2", 5335 "rc-input-number": "~7.3.9", 5336 "rc-mentions": "~1.10.0", 5337 "rc-menu": "~9.6.3", 5338 "rc-motion": "^2.6.1", 5339 "rc-notification": "~4.6.0", 5340 "rc-pagination": "~3.1.17", 5341 "rc-picker": "~2.6.11", 5342 "rc-progress": "~3.3.2", 5343 "rc-rate": "~2.9.0", 5344 "rc-resize-observer": "^1.2.0", 5345 "rc-segmented": "~2.1.0", 5346 "rc-select": "~14.1.13", 5347 "rc-slider": "~10.0.0", 5348 "rc-steps": "~4.1.0", 5349 "rc-switch": "~3.2.0", 5350 "rc-table": "~7.26.0", 5351 "rc-tabs": "~12.2.0", 5352 "rc-textarea": "~0.4.5", 5353 "rc-tooltip": "~5.2.0", 5354 "rc-tree": "~5.7.0", 5355 "rc-tree-select": "~5.5.0", 5356 "rc-trigger": "^5.2.10", 5357 "rc-upload": "~4.3.0", 5358 "rc-util": "^5.22.5", 5359 "scroll-into-view-if-needed": "^2.2.25" 5360 }, 5361 "funding": { 5362 "type": "opencollective", 5363 "url": "https://opencollective.com/ant-design" 5364 }, 5365 "peerDependencies": { 5366 "react": ">=16.9.0", 5367 "react-dom": ">=16.9.0" 5368 } 5369 }, 5255 5370 "node_modules/anymatch": { 5256 5371 "version": "3.1.2", … … 5313 5428 } 5314 5429 }, 5430 "node_modules/array-tree-filter": { 5431 "version": "2.1.0", 5432 "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", 5433 "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" 5434 }, 5315 5435 "node_modules/array-union": { 5316 5436 "version": "2.1.0", … … 5387 5507 "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", 5388 5508 "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" 5509 }, 5510 "node_modules/async-validator": { 5511 "version": "4.2.5", 5512 "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", 5513 "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" 5389 5514 }, 5390 5515 "node_modules/asynckit": { … … 6119 6244 "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" 6120 6245 }, 6246 "node_modules/classnames": { 6247 "version": "2.3.2", 6248 "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", 6249 "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" 6250 }, 6121 6251 "node_modules/clean-css": { 6122 6252 "version": "5.3.1", … … 6283 6413 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 6284 6414 "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 6415 }, 6416 "node_modules/compute-scroll-into-view": { 6417 "version": "1.0.17", 6418 "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", 6419 "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" 6285 6420 }, 6286 6421 "node_modules/concat-map": { … … 6360 6495 "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 6361 6496 "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 6497 }, 6498 "node_modules/copy-to-clipboard": { 6499 "version": "3.3.2", 6500 "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", 6501 "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", 6502 "dependencies": { 6503 "toggle-selection": "^1.0.6" 6504 } 6362 6505 }, 6363 6506 "node_modules/core-js": { … … 6850 6993 } 6851 6994 }, 6995 "node_modules/date-fns": { 6996 "version": "2.29.3", 6997 "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", 6998 "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", 6999 "engines": { 7000 "node": ">=0.11" 7001 }, 7002 "funding": { 7003 "type": "opencollective", 7004 "url": "https://opencollective.com/date-fns" 7005 } 7006 }, 7007 "node_modules/dayjs": { 7008 "version": "1.11.6", 7009 "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", 7010 "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" 7011 }, 6852 7012 "node_modules/debug": { 6853 7013 "version": "4.3.4", … … 7071 7231 "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", 7072 7232 "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" 7233 }, 7234 "node_modules/dom-align": { 7235 "version": "1.12.3", 7236 "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz", 7237 "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==" 7073 7238 }, 7074 7239 "node_modules/dom-converter": { … … 11891 12056 "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" 11892 12057 }, 12058 "node_modules/json2mq": { 12059 "version": "0.2.0", 12060 "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", 12061 "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", 12062 "dependencies": { 12063 "string-convert": "^0.2.0" 12064 } 12065 }, 11893 12066 "node_modules/json5": { 11894 12067 "version": "2.2.1", … … 12173 12346 } 12174 12347 }, 12348 "node_modules/memoize-one": { 12349 "version": "6.0.0", 12350 "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", 12351 "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" 12352 }, 12175 12353 "node_modules/merge-descriptors": { 12176 12354 "version": "1.0.1", … … 12354 12532 "bin": { 12355 12533 "mkdirp": "bin/cmd.js" 12534 } 12535 }, 12536 "node_modules/moment": { 12537 "version": "2.29.4", 12538 "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 12539 "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", 12540 "engines": { 12541 "node": "*" 12356 12542 } 12357 12543 }, … … 14400 14586 } 14401 14587 }, 14588 "node_modules/rc-align": { 14589 "version": "4.0.12", 14590 "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz", 14591 "integrity": "sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ==", 14592 "dependencies": { 14593 "@babel/runtime": "^7.10.1", 14594 "classnames": "2.x", 14595 "dom-align": "^1.7.0", 14596 "lodash": "^4.17.21", 14597 "rc-util": "^5.3.0", 14598 "resize-observer-polyfill": "^1.5.1" 14599 }, 14600 "peerDependencies": { 14601 "react": ">=16.9.0", 14602 "react-dom": ">=16.9.0" 14603 } 14604 }, 14605 "node_modules/rc-cascader": { 14606 "version": "3.7.0", 14607 "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.7.0.tgz", 14608 "integrity": "sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A==", 14609 "dependencies": { 14610 "@babel/runtime": "^7.12.5", 14611 "array-tree-filter": "^2.1.0", 14612 "classnames": "^2.3.1", 14613 "rc-select": "~14.1.0", 14614 "rc-tree": "~5.7.0", 14615 "rc-util": "^5.6.1" 14616 }, 14617 "peerDependencies": { 14618 "react": ">=16.9.0", 14619 "react-dom": ">=16.9.0" 14620 } 14621 }, 14622 "node_modules/rc-checkbox": { 14623 "version": "2.3.2", 14624 "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz", 14625 "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==", 14626 "dependencies": { 14627 "@babel/runtime": "^7.10.1", 14628 "classnames": "^2.2.1" 14629 }, 14630 "peerDependencies": { 14631 "react": ">=16.9.0", 14632 "react-dom": ">=16.9.0" 14633 } 14634 }, 14635 "node_modules/rc-collapse": { 14636 "version": "3.3.1", 14637 "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz", 14638 "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==", 14639 "dependencies": { 14640 "@babel/runtime": "^7.10.1", 14641 "classnames": "2.x", 14642 "rc-motion": "^2.3.4", 14643 "rc-util": "^5.2.1", 14644 "shallowequal": "^1.1.0" 14645 }, 14646 "peerDependencies": { 14647 "react": ">=16.9.0", 14648 "react-dom": ">=16.9.0" 14649 } 14650 }, 14651 "node_modules/rc-dialog": { 14652 "version": "8.9.0", 14653 "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz", 14654 "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==", 14655 "dependencies": { 14656 "@babel/runtime": "^7.10.1", 14657 "classnames": "^2.2.6", 14658 "rc-motion": "^2.3.0", 14659 "rc-util": "^5.21.0" 14660 }, 14661 "peerDependencies": { 14662 "react": ">=16.9.0", 14663 "react-dom": ">=16.9.0" 14664 } 14665 }, 14666 "node_modules/rc-drawer": { 14667 "version": "5.1.0", 14668 "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-5.1.0.tgz", 14669 "integrity": "sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw==", 14670 "dependencies": { 14671 "@babel/runtime": "^7.10.1", 14672 "classnames": "^2.2.6", 14673 "rc-motion": "^2.6.1", 14674 "rc-util": "^5.21.2" 14675 }, 14676 "peerDependencies": { 14677 "react": ">=16.9.0", 14678 "react-dom": ">=16.9.0" 14679 } 14680 }, 14681 "node_modules/rc-dropdown": { 14682 "version": "4.0.1", 14683 "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz", 14684 "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==", 14685 "dependencies": { 14686 "@babel/runtime": "^7.18.3", 14687 "classnames": "^2.2.6", 14688 "rc-trigger": "^5.3.1", 14689 "rc-util": "^5.17.0" 14690 }, 14691 "peerDependencies": { 14692 "react": ">=16.11.0", 14693 "react-dom": ">=16.11.0" 14694 } 14695 }, 14696 "node_modules/rc-field-form": { 14697 "version": "1.27.2", 14698 "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.27.2.tgz", 14699 "integrity": "sha512-NaTjkSB8JsHRgm52wkDorsDzFf2HH6GmCQ2AqkwO8zo+zIqybw8K1lkzDBMDJI8nw1pFuD46U5QsYZv4blYvdw==", 14700 "dependencies": { 14701 "@babel/runtime": "^7.18.0", 14702 "async-validator": "^4.1.0", 14703 "rc-util": "^5.8.0" 14704 }, 14705 "engines": { 14706 "node": ">=8.x" 14707 }, 14708 "peerDependencies": { 14709 "react": ">=16.9.0", 14710 "react-dom": ">=16.9.0" 14711 } 14712 }, 14713 "node_modules/rc-image": { 14714 "version": "5.7.1", 14715 "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.1.tgz", 14716 "integrity": "sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg==", 14717 "dependencies": { 14718 "@babel/runtime": "^7.11.2", 14719 "classnames": "^2.2.6", 14720 "rc-dialog": "~8.9.0", 14721 "rc-util": "^5.0.6" 14722 }, 14723 "peerDependencies": { 14724 "react": ">=16.9.0", 14725 "react-dom": ">=16.9.0" 14726 } 14727 }, 14728 "node_modules/rc-input": { 14729 "version": "0.1.2", 14730 "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.1.2.tgz", 14731 "integrity": "sha512-ZPmwcFspgfYpUfbSx3KnLk9gImBcLOrlQCr4oTJ4jBoIXgJLTfm26yelzRgBJewhkvD8uJbgX0sQ/yOzuOHnJg==", 14732 "dependencies": { 14733 "@babel/runtime": "^7.11.1", 14734 "classnames": "^2.2.1", 14735 "rc-util": "^5.18.1" 14736 }, 14737 "peerDependencies": { 14738 "react": ">=16.0.0", 14739 "react-dom": ">=16.0.0" 14740 } 14741 }, 14742 "node_modules/rc-input-number": { 14743 "version": "7.3.9", 14744 "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.9.tgz", 14745 "integrity": "sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA==", 14746 "dependencies": { 14747 "@babel/runtime": "^7.10.1", 14748 "classnames": "^2.2.5", 14749 "rc-util": "^5.23.0" 14750 }, 14751 "peerDependencies": { 14752 "react": ">=16.9.0", 14753 "react-dom": ">=16.9.0" 14754 } 14755 }, 14756 "node_modules/rc-mentions": { 14757 "version": "1.10.0", 14758 "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.10.0.tgz", 14759 "integrity": "sha512-oMlYWnwXSxP2NQVlgxOTzuG/u9BUc3ySY78K3/t7MNhJWpZzXTao+/Bic6tyZLuNCO89//hVQJBdaR2rnFQl6Q==", 14760 "dependencies": { 14761 "@babel/runtime": "^7.10.1", 14762 "classnames": "^2.2.6", 14763 "rc-menu": "~9.6.0", 14764 "rc-textarea": "^0.4.0", 14765 "rc-trigger": "^5.0.4", 14766 "rc-util": "^5.22.5" 14767 }, 14768 "peerDependencies": { 14769 "react": ">=16.9.0", 14770 "react-dom": ">=16.9.0" 14771 } 14772 }, 14773 "node_modules/rc-menu": { 14774 "version": "9.6.4", 14775 "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.4.tgz", 14776 "integrity": "sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==", 14777 "dependencies": { 14778 "@babel/runtime": "^7.10.1", 14779 "classnames": "2.x", 14780 "rc-motion": "^2.4.3", 14781 "rc-overflow": "^1.2.0", 14782 "rc-trigger": "^5.1.2", 14783 "rc-util": "^5.12.0", 14784 "shallowequal": "^1.1.0" 14785 }, 14786 "peerDependencies": { 14787 "react": ">=16.9.0", 14788 "react-dom": ">=16.9.0" 14789 } 14790 }, 14791 "node_modules/rc-motion": { 14792 "version": "2.6.2", 14793 "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.2.tgz", 14794 "integrity": "sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg==", 14795 "dependencies": { 14796 "@babel/runtime": "^7.11.1", 14797 "classnames": "^2.2.1", 14798 "rc-util": "^5.21.0" 14799 }, 14800 "peerDependencies": { 14801 "react": ">=16.9.0", 14802 "react-dom": ">=16.9.0" 14803 } 14804 }, 14805 "node_modules/rc-notification": { 14806 "version": "4.6.0", 14807 "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz", 14808 "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==", 14809 "dependencies": { 14810 "@babel/runtime": "^7.10.1", 14811 "classnames": "2.x", 14812 "rc-motion": "^2.2.0", 14813 "rc-util": "^5.20.1" 14814 }, 14815 "engines": { 14816 "node": ">=8.x" 14817 }, 14818 "peerDependencies": { 14819 "react": ">=16.9.0", 14820 "react-dom": ">=16.9.0" 14821 } 14822 }, 14823 "node_modules/rc-overflow": { 14824 "version": "1.2.8", 14825 "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.8.tgz", 14826 "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==", 14827 "dependencies": { 14828 "@babel/runtime": "^7.11.1", 14829 "classnames": "^2.2.1", 14830 "rc-resize-observer": "^1.0.0", 14831 "rc-util": "^5.19.2" 14832 }, 14833 "peerDependencies": { 14834 "react": ">=16.9.0", 14835 "react-dom": ">=16.9.0" 14836 } 14837 }, 14838 "node_modules/rc-pagination": { 14839 "version": "3.1.17", 14840 "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz", 14841 "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==", 14842 "dependencies": { 14843 "@babel/runtime": "^7.10.1", 14844 "classnames": "^2.2.1" 14845 }, 14846 "peerDependencies": { 14847 "react": ">=16.9.0", 14848 "react-dom": ">=16.9.0" 14849 } 14850 }, 14851 "node_modules/rc-picker": { 14852 "version": "2.6.11", 14853 "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.11.tgz", 14854 "integrity": "sha512-INJ7ULu+Kj4UgqbcqE8Q+QpMw55xFf9kkyLBHJFk0ihjJpAV4glialRfqHE7k4KX2BWYPQfpILwhwR14x2EiRQ==", 14855 "dependencies": { 14856 "@babel/runtime": "^7.10.1", 14857 "classnames": "^2.2.1", 14858 "date-fns": "2.x", 14859 "dayjs": "1.x", 14860 "moment": "^2.24.0", 14861 "rc-trigger": "^5.0.4", 14862 "rc-util": "^5.4.0", 14863 "shallowequal": "^1.1.0" 14864 }, 14865 "engines": { 14866 "node": ">=8.x" 14867 }, 14868 "peerDependencies": { 14869 "react": ">=16.9.0", 14870 "react-dom": ">=16.9.0" 14871 } 14872 }, 14873 "node_modules/rc-progress": { 14874 "version": "3.3.3", 14875 "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz", 14876 "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==", 14877 "dependencies": { 14878 "@babel/runtime": "^7.10.1", 14879 "classnames": "^2.2.6", 14880 "rc-util": "^5.16.1" 14881 }, 14882 "peerDependencies": { 14883 "react": ">=16.9.0", 14884 "react-dom": ">=16.9.0" 14885 } 14886 }, 14887 "node_modules/rc-rate": { 14888 "version": "2.9.2", 14889 "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.2.tgz", 14890 "integrity": "sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g==", 14891 "dependencies": { 14892 "@babel/runtime": "^7.10.1", 14893 "classnames": "^2.2.5", 14894 "rc-util": "^5.0.1" 14895 }, 14896 "engines": { 14897 "node": ">=8.x" 14898 }, 14899 "peerDependencies": { 14900 "react": ">=16.9.0", 14901 "react-dom": ">=16.9.0" 14902 } 14903 }, 14904 "node_modules/rc-resize-observer": { 14905 "version": "1.2.0", 14906 "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz", 14907 "integrity": "sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ==", 14908 "dependencies": { 14909 "@babel/runtime": "^7.10.1", 14910 "classnames": "^2.2.1", 14911 "rc-util": "^5.15.0", 14912 "resize-observer-polyfill": "^1.5.1" 14913 }, 14914 "peerDependencies": { 14915 "react": ">=16.9.0", 14916 "react-dom": ">=16.9.0" 14917 } 14918 }, 14919 "node_modules/rc-segmented": { 14920 "version": "2.1.0", 14921 "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz", 14922 "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==", 14923 "dependencies": { 14924 "@babel/runtime": "^7.11.1", 14925 "classnames": "^2.2.1", 14926 "rc-motion": "^2.4.4", 14927 "rc-util": "^5.17.0" 14928 }, 14929 "peerDependencies": { 14930 "react": ">=16.0.0", 14931 "react-dom": ">=16.0.0" 14932 } 14933 }, 14934 "node_modules/rc-select": { 14935 "version": "14.1.13", 14936 "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.13.tgz", 14937 "integrity": "sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg==", 14938 "dependencies": { 14939 "@babel/runtime": "^7.10.1", 14940 "classnames": "2.x", 14941 "rc-motion": "^2.0.1", 14942 "rc-overflow": "^1.0.0", 14943 "rc-trigger": "^5.0.4", 14944 "rc-util": "^5.16.1", 14945 "rc-virtual-list": "^3.2.0" 14946 }, 14947 "engines": { 14948 "node": ">=8.x" 14949 }, 14950 "peerDependencies": { 14951 "react": "*", 14952 "react-dom": "*" 14953 } 14954 }, 14955 "node_modules/rc-slider": { 14956 "version": "10.0.1", 14957 "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.0.1.tgz", 14958 "integrity": "sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q==", 14959 "dependencies": { 14960 "@babel/runtime": "^7.10.1", 14961 "classnames": "^2.2.5", 14962 "rc-util": "^5.18.1", 14963 "shallowequal": "^1.1.0" 14964 }, 14965 "engines": { 14966 "node": ">=8.x" 14967 }, 14968 "peerDependencies": { 14969 "react": ">=16.9.0", 14970 "react-dom": ">=16.9.0" 14971 } 14972 }, 14973 "node_modules/rc-steps": { 14974 "version": "4.1.4", 14975 "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz", 14976 "integrity": "sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w==", 14977 "dependencies": { 14978 "@babel/runtime": "^7.10.2", 14979 "classnames": "^2.2.3", 14980 "rc-util": "^5.0.1" 14981 }, 14982 "engines": { 14983 "node": ">=8.x" 14984 }, 14985 "peerDependencies": { 14986 "react": ">=16.9.0", 14987 "react-dom": ">=16.9.0" 14988 } 14989 }, 14990 "node_modules/rc-switch": { 14991 "version": "3.2.2", 14992 "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz", 14993 "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==", 14994 "dependencies": { 14995 "@babel/runtime": "^7.10.1", 14996 "classnames": "^2.2.1", 14997 "rc-util": "^5.0.1" 14998 }, 14999 "peerDependencies": { 15000 "react": ">=16.9.0", 15001 "react-dom": ">=16.9.0" 15002 } 15003 }, 15004 "node_modules/rc-table": { 15005 "version": "7.26.0", 15006 "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.26.0.tgz", 15007 "integrity": "sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ==", 15008 "dependencies": { 15009 "@babel/runtime": "^7.10.1", 15010 "classnames": "^2.2.5", 15011 "rc-resize-observer": "^1.1.0", 15012 "rc-util": "^5.22.5", 15013 "shallowequal": "^1.1.0" 15014 }, 15015 "engines": { 15016 "node": ">=8.x" 15017 }, 15018 "peerDependencies": { 15019 "react": ">=16.9.0", 15020 "react-dom": ">=16.9.0" 15021 } 15022 }, 15023 "node_modules/rc-tabs": { 15024 "version": "12.2.1", 15025 "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.2.1.tgz", 15026 "integrity": "sha512-09pVv4kN8VFqp6THceEmxOW8PAShQC08hrroeVYP4Y8YBFaP1PIWdyFL01czcbyz5YZFj9flZ7aljMaAl0jLVg==", 15027 "dependencies": { 15028 "@babel/runtime": "^7.11.2", 15029 "classnames": "2.x", 15030 "rc-dropdown": "~4.0.0", 15031 "rc-menu": "~9.6.0", 15032 "rc-motion": "^2.6.2", 15033 "rc-resize-observer": "^1.0.0", 15034 "rc-util": "^5.5.0" 15035 }, 15036 "engines": { 15037 "node": ">=8.x" 15038 }, 15039 "peerDependencies": { 15040 "react": ">=16.9.0", 15041 "react-dom": ">=16.9.0" 15042 } 15043 }, 15044 "node_modules/rc-textarea": { 15045 "version": "0.4.5", 15046 "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.4.5.tgz", 15047 "integrity": "sha512-WHeJRgUlloNyVgTsItMrIXwMhU6P3NmrUDkxX+JRwEpJjECsKtZNlNcXe9pHNLCaYQ3Z1cVCfsClhgDDgJ2kFQ==", 15048 "dependencies": { 15049 "@babel/runtime": "^7.10.1", 15050 "classnames": "^2.2.1", 15051 "rc-resize-observer": "^1.0.0", 15052 "rc-util": "^5.7.0", 15053 "shallowequal": "^1.1.0" 15054 }, 15055 "peerDependencies": { 15056 "react": ">=16.9.0", 15057 "react-dom": ">=16.9.0" 15058 } 15059 }, 15060 "node_modules/rc-tooltip": { 15061 "version": "5.2.2", 15062 "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.2.2.tgz", 15063 "integrity": "sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==", 15064 "dependencies": { 15065 "@babel/runtime": "^7.11.2", 15066 "classnames": "^2.3.1", 15067 "rc-trigger": "^5.0.0" 15068 }, 15069 "peerDependencies": { 15070 "react": ">=16.9.0", 15071 "react-dom": ">=16.9.0" 15072 } 15073 }, 15074 "node_modules/rc-tree": { 15075 "version": "5.7.0", 15076 "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.0.tgz", 15077 "integrity": "sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg==", 15078 "dependencies": { 15079 "@babel/runtime": "^7.10.1", 15080 "classnames": "2.x", 15081 "rc-motion": "^2.0.1", 15082 "rc-util": "^5.16.1", 15083 "rc-virtual-list": "^3.4.8" 15084 }, 15085 "engines": { 15086 "node": ">=10.x" 15087 }, 15088 "peerDependencies": { 15089 "react": "*", 15090 "react-dom": "*" 15091 } 15092 }, 15093 "node_modules/rc-tree-select": { 15094 "version": "5.5.2", 15095 "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.5.2.tgz", 15096 "integrity": "sha512-toxkzVhkWQ2wvInOhHwmyEpCCi9osnoRQmN0trKvdvyzLattCw63F2T+V/dS2d/xUkrw6Zr1Y2J0/xP57x/jYQ==", 15097 "dependencies": { 15098 "@babel/runtime": "^7.10.1", 15099 "classnames": "2.x", 15100 "rc-select": "~14.1.0", 15101 "rc-tree": "~5.7.0", 15102 "rc-util": "^5.16.1" 15103 }, 15104 "peerDependencies": { 15105 "react": "*", 15106 "react-dom": "*" 15107 } 15108 }, 15109 "node_modules/rc-trigger": { 15110 "version": "5.3.1", 15111 "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz", 15112 "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==", 15113 "dependencies": { 15114 "@babel/runtime": "^7.18.3", 15115 "classnames": "^2.2.6", 15116 "rc-align": "^4.0.0", 15117 "rc-motion": "^2.0.0", 15118 "rc-util": "^5.19.2" 15119 }, 15120 "engines": { 15121 "node": ">=8.x" 15122 }, 15123 "peerDependencies": { 15124 "react": ">=16.9.0", 15125 "react-dom": ">=16.9.0" 15126 } 15127 }, 15128 "node_modules/rc-upload": { 15129 "version": "4.3.4", 15130 "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.4.tgz", 15131 "integrity": "sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ==", 15132 "dependencies": { 15133 "@babel/runtime": "^7.18.3", 15134 "classnames": "^2.2.5", 15135 "rc-util": "^5.2.0" 15136 }, 15137 "peerDependencies": { 15138 "react": ">=16.9.0", 15139 "react-dom": ">=16.9.0" 15140 } 15141 }, 15142 "node_modules/rc-util": { 15143 "version": "5.24.4", 15144 "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.4.tgz", 15145 "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==", 15146 "dependencies": { 15147 "@babel/runtime": "^7.18.3", 15148 "react-is": "^16.12.0", 15149 "shallowequal": "^1.1.0" 15150 }, 15151 "peerDependencies": { 15152 "react": ">=16.9.0", 15153 "react-dom": ">=16.9.0" 15154 } 15155 }, 15156 "node_modules/rc-util/node_modules/react-is": { 15157 "version": "16.13.1", 15158 "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 15159 "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" 15160 }, 15161 "node_modules/rc-virtual-list": { 15162 "version": "3.4.10", 15163 "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.10.tgz", 15164 "integrity": "sha512-Jv0cgJxJ+8F/YViW8WGs/jQF2rmT8RUcJ5uDJs5MOFLTYLAvCpM/xU+Zu6EpCun50fmovhXiItQctcfE2UY3Aw==", 15165 "dependencies": { 15166 "classnames": "^2.2.6", 15167 "rc-resize-observer": "^1.0.0", 15168 "rc-util": "^5.15.0" 15169 }, 15170 "engines": { 15171 "node": ">=8.x" 15172 }, 15173 "peerDependencies": { 15174 "react": "*", 15175 "react-dom": "*" 15176 } 15177 }, 14402 15178 "node_modules/react": { 14403 15179 "version": "18.2.0", … … 14895 15671 "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" 14896 15672 }, 15673 "node_modules/resize-observer-polyfill": { 15674 "version": "1.5.1", 15675 "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", 15676 "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" 15677 }, 14897 15678 "node_modules/resolve": { 14898 15679 "version": "1.22.1", … … 15206 15987 "type": "opencollective", 15207 15988 "url": "https://opencollective.com/webpack" 15989 } 15990 }, 15991 "node_modules/scroll-into-view-if-needed": { 15992 "version": "2.2.29", 15993 "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz", 15994 "integrity": "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==", 15995 "dependencies": { 15996 "compute-scroll-into-view": "^1.0.17" 15208 15997 } 15209 15998 }, … … 15376 16165 "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 15377 16166 }, 16167 "node_modules/shallowequal": { 16168 "version": "1.1.0", 16169 "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", 16170 "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" 16171 }, 15378 16172 "node_modules/shebang-command": { 15379 16173 "version": "2.0.0", … … 15601 16395 } 15602 16396 ] 16397 }, 16398 "node_modules/string-convert": { 16399 "version": "0.2.1", 16400 "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", 16401 "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" 15603 16402 }, 15604 16403 "node_modules/string-length": { … … 16146 16945 "node": ">=8.0" 16147 16946 } 16947 }, 16948 "node_modules/toggle-selection": { 16949 "version": "1.0.6", 16950 "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", 16951 "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" 16148 16952 }, 16149 16953 "node_modules/toidentifier": { … … 17442 18246 "@jridgewell/gen-mapping": "^0.1.0", 17443 18247 "@jridgewell/trace-mapping": "^0.3.9" 18248 } 18249 }, 18250 "@ant-design/colors": { 18251 "version": "6.0.0", 18252 "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", 18253 "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", 18254 "requires": { 18255 "@ctrl/tinycolor": "^3.4.0" 18256 } 18257 }, 18258 "@ant-design/icons": { 18259 "version": "4.7.0", 18260 "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.7.0.tgz", 18261 "integrity": "sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g==", 18262 "requires": { 18263 "@ant-design/colors": "^6.0.0", 18264 "@ant-design/icons-svg": "^4.2.1", 18265 "@babel/runtime": "^7.11.2", 18266 "classnames": "^2.2.6", 18267 "rc-util": "^5.9.4" 18268 } 18269 }, 18270 "@ant-design/icons-svg": { 18271 "version": "4.2.1", 18272 "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz", 18273 "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" 18274 }, 18275 "@ant-design/react-slick": { 18276 "version": "0.29.2", 18277 "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz", 18278 "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==", 18279 "requires": { 18280 "@babel/runtime": "^7.10.4", 18281 "classnames": "^2.2.5", 18282 "json2mq": "^0.2.0", 18283 "lodash": "^4.17.21", 18284 "resize-observer-polyfill": "^1.5.1" 17444 18285 } 17445 18286 }, … … 18813 19654 "requires": {} 18814 19655 }, 19656 "@ctrl/tinycolor": { 19657 "version": "3.4.1", 19658 "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", 19659 "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" 19660 }, 18815 19661 "@emotion/babel-plugin": { 18816 19662 "version": "11.10.2", … … 21032 21878 } 21033 21879 }, 21880 "antd": { 21881 "version": "4.23.6", 21882 "resolved": "https://registry.npmjs.org/antd/-/antd-4.23.6.tgz", 21883 "integrity": "sha512-AYH57cWBDe1ChtbnvG8i9dpKG4WnjE3AG0zIKpXByFNnxsr4saV6/19ihE8/ImSGpohN4E2zTXmo7R5/MyVRKQ==", 21884 "requires": { 21885 "@ant-design/colors": "^6.0.0", 21886 "@ant-design/icons": "^4.7.0", 21887 "@ant-design/react-slick": "~0.29.1", 21888 "@babel/runtime": "^7.18.3", 21889 "@ctrl/tinycolor": "^3.4.0", 21890 "classnames": "^2.2.6", 21891 "copy-to-clipboard": "^3.2.0", 21892 "lodash": "^4.17.21", 21893 "memoize-one": "^6.0.0", 21894 "moment": "^2.29.2", 21895 "rc-cascader": "~3.7.0", 21896 "rc-checkbox": "~2.3.0", 21897 "rc-collapse": "~3.3.0", 21898 "rc-dialog": "~8.9.0", 21899 "rc-drawer": "~5.1.0", 21900 "rc-dropdown": "~4.0.0", 21901 "rc-field-form": "~1.27.0", 21902 "rc-image": "~5.7.0", 21903 "rc-input": "~0.1.2", 21904 "rc-input-number": "~7.3.9", 21905 "rc-mentions": "~1.10.0", 21906 "rc-menu": "~9.6.3", 21907 "rc-motion": "^2.6.1", 21908 "rc-notification": "~4.6.0", 21909 "rc-pagination": "~3.1.17", 21910 "rc-picker": "~2.6.11", 21911 "rc-progress": "~3.3.2", 21912 "rc-rate": "~2.9.0", 21913 "rc-resize-observer": "^1.2.0", 21914 "rc-segmented": "~2.1.0", 21915 "rc-select": "~14.1.13", 21916 "rc-slider": "~10.0.0", 21917 "rc-steps": "~4.1.0", 21918 "rc-switch": "~3.2.0", 21919 "rc-table": "~7.26.0", 21920 "rc-tabs": "~12.2.0", 21921 "rc-textarea": "~0.4.5", 21922 "rc-tooltip": "~5.2.0", 21923 "rc-tree": "~5.7.0", 21924 "rc-tree-select": "~5.5.0", 21925 "rc-trigger": "^5.2.10", 21926 "rc-upload": "~4.3.0", 21927 "rc-util": "^5.22.5", 21928 "scroll-into-view-if-needed": "^2.2.25" 21929 } 21930 }, 21034 21931 "anymatch": { 21035 21932 "version": "3.1.2", … … 21080 21977 } 21081 21978 }, 21979 "array-tree-filter": { 21980 "version": "2.1.0", 21981 "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", 21982 "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" 21983 }, 21082 21984 "array-union": { 21083 21985 "version": "2.1.0", … … 21133 22035 "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", 21134 22036 "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" 22037 }, 22038 "async-validator": { 22039 "version": "4.2.5", 22040 "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", 22041 "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" 21135 22042 }, 21136 22043 "asynckit": { … … 21677 22584 "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" 21678 22585 }, 22586 "classnames": { 22587 "version": "2.3.2", 22588 "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", 22589 "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" 22590 }, 21679 22591 "clean-css": { 21680 22592 "version": "5.3.1", … … 21815 22727 } 21816 22728 }, 22729 "compute-scroll-into-view": { 22730 "version": "1.0.17", 22731 "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", 22732 "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" 22733 }, 21817 22734 "concat-map": { 21818 22735 "version": "0.0.1", … … 21867 22784 "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 21868 22785 "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 22786 }, 22787 "copy-to-clipboard": { 22788 "version": "3.3.2", 22789 "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", 22790 "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", 22791 "requires": { 22792 "toggle-selection": "^1.0.6" 22793 } 21869 22794 }, 21870 22795 "core-js": { … … 22198 23123 } 22199 23124 }, 23125 "date-fns": { 23126 "version": "2.29.3", 23127 "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", 23128 "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" 23129 }, 23130 "dayjs": { 23131 "version": "1.11.6", 23132 "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", 23133 "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" 23134 }, 22200 23135 "debug": { 22201 23136 "version": "4.3.4", … … 22360 23295 "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", 22361 23296 "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" 23297 }, 23298 "dom-align": { 23299 "version": "1.12.3", 23300 "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz", 23301 "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==" 22362 23302 }, 22363 23303 "dom-converter": { … … 25851 26791 "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" 25852 26792 }, 26793 "json2mq": { 26794 "version": "0.2.0", 26795 "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", 26796 "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", 26797 "requires": { 26798 "string-convert": "^0.2.0" 26799 } 26800 }, 25853 26801 "json5": { 25854 26802 "version": "2.2.1", … … 26066 27014 "fs-monkey": "^1.0.3" 26067 27015 } 27016 }, 27017 "memoize-one": { 27018 "version": "6.0.0", 27019 "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", 27020 "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" 26068 27021 }, 26069 27022 "merge-descriptors": { … … 26194 27147 "minimist": "^1.2.6" 26195 27148 } 27149 }, 27150 "moment": { 27151 "version": "2.29.4", 27152 "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 27153 "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" 26196 27154 }, 26197 27155 "ms": { … … 27479 28437 } 27480 28438 }, 28439 "rc-align": { 28440 "version": "4.0.12", 28441 "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz", 28442 "integrity": "sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ==", 28443 "requires": { 28444 "@babel/runtime": "^7.10.1", 28445 "classnames": "2.x", 28446 "dom-align": "^1.7.0", 28447 "lodash": "^4.17.21", 28448 "rc-util": "^5.3.0", 28449 "resize-observer-polyfill": "^1.5.1" 28450 } 28451 }, 28452 "rc-cascader": { 28453 "version": "3.7.0", 28454 "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.7.0.tgz", 28455 "integrity": "sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A==", 28456 "requires": { 28457 "@babel/runtime": "^7.12.5", 28458 "array-tree-filter": "^2.1.0", 28459 "classnames": "^2.3.1", 28460 "rc-select": "~14.1.0", 28461 "rc-tree": "~5.7.0", 28462 "rc-util": "^5.6.1" 28463 } 28464 }, 28465 "rc-checkbox": { 28466 "version": "2.3.2", 28467 "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz", 28468 "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==", 28469 "requires": { 28470 "@babel/runtime": "^7.10.1", 28471 "classnames": "^2.2.1" 28472 } 28473 }, 28474 "rc-collapse": { 28475 "version": "3.3.1", 28476 "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz", 28477 "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==", 28478 "requires": { 28479 "@babel/runtime": "^7.10.1", 28480 "classnames": "2.x", 28481 "rc-motion": "^2.3.4", 28482 "rc-util": "^5.2.1", 28483 "shallowequal": "^1.1.0" 28484 } 28485 }, 28486 "rc-dialog": { 28487 "version": "8.9.0", 28488 "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz", 28489 "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==", 28490 "requires": { 28491 "@babel/runtime": "^7.10.1", 28492 "classnames": "^2.2.6", 28493 "rc-motion": "^2.3.0", 28494 "rc-util": "^5.21.0" 28495 } 28496 }, 28497 "rc-drawer": { 28498 "version": "5.1.0", 28499 "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-5.1.0.tgz", 28500 "integrity": "sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw==", 28501 "requires": { 28502 "@babel/runtime": "^7.10.1", 28503 "classnames": "^2.2.6", 28504 "rc-motion": "^2.6.1", 28505 "rc-util": "^5.21.2" 28506 } 28507 }, 28508 "rc-dropdown": { 28509 "version": "4.0.1", 28510 "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz", 28511 "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==", 28512 "requires": { 28513 "@babel/runtime": "^7.18.3", 28514 "classnames": "^2.2.6", 28515 "rc-trigger": "^5.3.1", 28516 "rc-util": "^5.17.0" 28517 } 28518 }, 28519 "rc-field-form": { 28520 "version": "1.27.2", 28521 "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.27.2.tgz", 28522 "integrity": "sha512-NaTjkSB8JsHRgm52wkDorsDzFf2HH6GmCQ2AqkwO8zo+zIqybw8K1lkzDBMDJI8nw1pFuD46U5QsYZv4blYvdw==", 28523 "requires": { 28524 "@babel/runtime": "^7.18.0", 28525 "async-validator": "^4.1.0", 28526 "rc-util": "^5.8.0" 28527 } 28528 }, 28529 "rc-image": { 28530 "version": "5.7.1", 28531 "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.1.tgz", 28532 "integrity": "sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg==", 28533 "requires": { 28534 "@babel/runtime": "^7.11.2", 28535 "classnames": "^2.2.6", 28536 "rc-dialog": "~8.9.0", 28537 "rc-util": "^5.0.6" 28538 } 28539 }, 28540 "rc-input": { 28541 "version": "0.1.2", 28542 "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.1.2.tgz", 28543 "integrity": "sha512-ZPmwcFspgfYpUfbSx3KnLk9gImBcLOrlQCr4oTJ4jBoIXgJLTfm26yelzRgBJewhkvD8uJbgX0sQ/yOzuOHnJg==", 28544 "requires": { 28545 "@babel/runtime": "^7.11.1", 28546 "classnames": "^2.2.1", 28547 "rc-util": "^5.18.1" 28548 } 28549 }, 28550 "rc-input-number": { 28551 "version": "7.3.9", 28552 "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.9.tgz", 28553 "integrity": "sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA==", 28554 "requires": { 28555 "@babel/runtime": "^7.10.1", 28556 "classnames": "^2.2.5", 28557 "rc-util": "^5.23.0" 28558 } 28559 }, 28560 "rc-mentions": { 28561 "version": "1.10.0", 28562 "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.10.0.tgz", 28563 "integrity": "sha512-oMlYWnwXSxP2NQVlgxOTzuG/u9BUc3ySY78K3/t7MNhJWpZzXTao+/Bic6tyZLuNCO89//hVQJBdaR2rnFQl6Q==", 28564 "requires": { 28565 "@babel/runtime": "^7.10.1", 28566 "classnames": "^2.2.6", 28567 "rc-menu": "~9.6.0", 28568 "rc-textarea": "^0.4.0", 28569 "rc-trigger": "^5.0.4", 28570 "rc-util": "^5.22.5" 28571 } 28572 }, 28573 "rc-menu": { 28574 "version": "9.6.4", 28575 "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.4.tgz", 28576 "integrity": "sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==", 28577 "requires": { 28578 "@babel/runtime": "^7.10.1", 28579 "classnames": "2.x", 28580 "rc-motion": "^2.4.3", 28581 "rc-overflow": "^1.2.0", 28582 "rc-trigger": "^5.1.2", 28583 "rc-util": "^5.12.0", 28584 "shallowequal": "^1.1.0" 28585 } 28586 }, 28587 "rc-motion": { 28588 "version": "2.6.2", 28589 "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.2.tgz", 28590 "integrity": "sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg==", 28591 "requires": { 28592 "@babel/runtime": "^7.11.1", 28593 "classnames": "^2.2.1", 28594 "rc-util": "^5.21.0" 28595 } 28596 }, 28597 "rc-notification": { 28598 "version": "4.6.0", 28599 "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz", 28600 "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==", 28601 "requires": { 28602 "@babel/runtime": "^7.10.1", 28603 "classnames": "2.x", 28604 "rc-motion": "^2.2.0", 28605 "rc-util": "^5.20.1" 28606 } 28607 }, 28608 "rc-overflow": { 28609 "version": "1.2.8", 28610 "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.8.tgz", 28611 "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==", 28612 "requires": { 28613 "@babel/runtime": "^7.11.1", 28614 "classnames": "^2.2.1", 28615 "rc-resize-observer": "^1.0.0", 28616 "rc-util": "^5.19.2" 28617 } 28618 }, 28619 "rc-pagination": { 28620 "version": "3.1.17", 28621 "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz", 28622 "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==", 28623 "requires": { 28624 "@babel/runtime": "^7.10.1", 28625 "classnames": "^2.2.1" 28626 } 28627 }, 28628 "rc-picker": { 28629 "version": "2.6.11", 28630 "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.11.tgz", 28631 "integrity": "sha512-INJ7ULu+Kj4UgqbcqE8Q+QpMw55xFf9kkyLBHJFk0ihjJpAV4glialRfqHE7k4KX2BWYPQfpILwhwR14x2EiRQ==", 28632 "requires": { 28633 "@babel/runtime": "^7.10.1", 28634 "classnames": "^2.2.1", 28635 "date-fns": "2.x", 28636 "dayjs": "1.x", 28637 "moment": "^2.24.0", 28638 "rc-trigger": "^5.0.4", 28639 "rc-util": "^5.4.0", 28640 "shallowequal": "^1.1.0" 28641 } 28642 }, 28643 "rc-progress": { 28644 "version": "3.3.3", 28645 "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz", 28646 "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==", 28647 "requires": { 28648 "@babel/runtime": "^7.10.1", 28649 "classnames": "^2.2.6", 28650 "rc-util": "^5.16.1" 28651 } 28652 }, 28653 "rc-rate": { 28654 "version": "2.9.2", 28655 "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.2.tgz", 28656 "integrity": "sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g==", 28657 "requires": { 28658 "@babel/runtime": "^7.10.1", 28659 "classnames": "^2.2.5", 28660 "rc-util": "^5.0.1" 28661 } 28662 }, 28663 "rc-resize-observer": { 28664 "version": "1.2.0", 28665 "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz", 28666 "integrity": "sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ==", 28667 "requires": { 28668 "@babel/runtime": "^7.10.1", 28669 "classnames": "^2.2.1", 28670 "rc-util": "^5.15.0", 28671 "resize-observer-polyfill": "^1.5.1" 28672 } 28673 }, 28674 "rc-segmented": { 28675 "version": "2.1.0", 28676 "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz", 28677 "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==", 28678 "requires": { 28679 "@babel/runtime": "^7.11.1", 28680 "classnames": "^2.2.1", 28681 "rc-motion": "^2.4.4", 28682 "rc-util": "^5.17.0" 28683 } 28684 }, 28685 "rc-select": { 28686 "version": "14.1.13", 28687 "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.13.tgz", 28688 "integrity": "sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg==", 28689 "requires": { 28690 "@babel/runtime": "^7.10.1", 28691 "classnames": "2.x", 28692 "rc-motion": "^2.0.1", 28693 "rc-overflow": "^1.0.0", 28694 "rc-trigger": "^5.0.4", 28695 "rc-util": "^5.16.1", 28696 "rc-virtual-list": "^3.2.0" 28697 } 28698 }, 28699 "rc-slider": { 28700 "version": "10.0.1", 28701 "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.0.1.tgz", 28702 "integrity": "sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q==", 28703 "requires": { 28704 "@babel/runtime": "^7.10.1", 28705 "classnames": "^2.2.5", 28706 "rc-util": "^5.18.1", 28707 "shallowequal": "^1.1.0" 28708 } 28709 }, 28710 "rc-steps": { 28711 "version": "4.1.4", 28712 "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz", 28713 "integrity": "sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w==", 28714 "requires": { 28715 "@babel/runtime": "^7.10.2", 28716 "classnames": "^2.2.3", 28717 "rc-util": "^5.0.1" 28718 } 28719 }, 28720 "rc-switch": { 28721 "version": "3.2.2", 28722 "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz", 28723 "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==", 28724 "requires": { 28725 "@babel/runtime": "^7.10.1", 28726 "classnames": "^2.2.1", 28727 "rc-util": "^5.0.1" 28728 } 28729 }, 28730 "rc-table": { 28731 "version": "7.26.0", 28732 "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.26.0.tgz", 28733 "integrity": "sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ==", 28734 "requires": { 28735 "@babel/runtime": "^7.10.1", 28736 "classnames": "^2.2.5", 28737 "rc-resize-observer": "^1.1.0", 28738 "rc-util": "^5.22.5", 28739 "shallowequal": "^1.1.0" 28740 } 28741 }, 28742 "rc-tabs": { 28743 "version": "12.2.1", 28744 "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.2.1.tgz", 28745 "integrity": "sha512-09pVv4kN8VFqp6THceEmxOW8PAShQC08hrroeVYP4Y8YBFaP1PIWdyFL01czcbyz5YZFj9flZ7aljMaAl0jLVg==", 28746 "requires": { 28747 "@babel/runtime": "^7.11.2", 28748 "classnames": "2.x", 28749 "rc-dropdown": "~4.0.0", 28750 "rc-menu": "~9.6.0", 28751 "rc-motion": "^2.6.2", 28752 "rc-resize-observer": "^1.0.0", 28753 "rc-util": "^5.5.0" 28754 } 28755 }, 28756 "rc-textarea": { 28757 "version": "0.4.5", 28758 "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.4.5.tgz", 28759 "integrity": "sha512-WHeJRgUlloNyVgTsItMrIXwMhU6P3NmrUDkxX+JRwEpJjECsKtZNlNcXe9pHNLCaYQ3Z1cVCfsClhgDDgJ2kFQ==", 28760 "requires": { 28761 "@babel/runtime": "^7.10.1", 28762 "classnames": "^2.2.1", 28763 "rc-resize-observer": "^1.0.0", 28764 "rc-util": "^5.7.0", 28765 "shallowequal": "^1.1.0" 28766 } 28767 }, 28768 "rc-tooltip": { 28769 "version": "5.2.2", 28770 "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.2.2.tgz", 28771 "integrity": "sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==", 28772 "requires": { 28773 "@babel/runtime": "^7.11.2", 28774 "classnames": "^2.3.1", 28775 "rc-trigger": "^5.0.0" 28776 } 28777 }, 28778 "rc-tree": { 28779 "version": "5.7.0", 28780 "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.0.tgz", 28781 "integrity": "sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg==", 28782 "requires": { 28783 "@babel/runtime": "^7.10.1", 28784 "classnames": "2.x", 28785 "rc-motion": "^2.0.1", 28786 "rc-util": "^5.16.1", 28787 "rc-virtual-list": "^3.4.8" 28788 } 28789 }, 28790 "rc-tree-select": { 28791 "version": "5.5.2", 28792 "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.5.2.tgz", 28793 "integrity": "sha512-toxkzVhkWQ2wvInOhHwmyEpCCi9osnoRQmN0trKvdvyzLattCw63F2T+V/dS2d/xUkrw6Zr1Y2J0/xP57x/jYQ==", 28794 "requires": { 28795 "@babel/runtime": "^7.10.1", 28796 "classnames": "2.x", 28797 "rc-select": "~14.1.0", 28798 "rc-tree": "~5.7.0", 28799 "rc-util": "^5.16.1" 28800 } 28801 }, 28802 "rc-trigger": { 28803 "version": "5.3.1", 28804 "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz", 28805 "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==", 28806 "requires": { 28807 "@babel/runtime": "^7.18.3", 28808 "classnames": "^2.2.6", 28809 "rc-align": "^4.0.0", 28810 "rc-motion": "^2.0.0", 28811 "rc-util": "^5.19.2" 28812 } 28813 }, 28814 "rc-upload": { 28815 "version": "4.3.4", 28816 "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.4.tgz", 28817 "integrity": "sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ==", 28818 "requires": { 28819 "@babel/runtime": "^7.18.3", 28820 "classnames": "^2.2.5", 28821 "rc-util": "^5.2.0" 28822 } 28823 }, 28824 "rc-util": { 28825 "version": "5.24.4", 28826 "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.4.tgz", 28827 "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==", 28828 "requires": { 28829 "@babel/runtime": "^7.18.3", 28830 "react-is": "^16.12.0", 28831 "shallowequal": "^1.1.0" 28832 }, 28833 "dependencies": { 28834 "react-is": { 28835 "version": "16.13.1", 28836 "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 28837 "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" 28838 } 28839 } 28840 }, 28841 "rc-virtual-list": { 28842 "version": "3.4.10", 28843 "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.10.tgz", 28844 "integrity": "sha512-Jv0cgJxJ+8F/YViW8WGs/jQF2rmT8RUcJ5uDJs5MOFLTYLAvCpM/xU+Zu6EpCun50fmovhXiItQctcfE2UY3Aw==", 28845 "requires": { 28846 "classnames": "^2.2.6", 28847 "rc-resize-observer": "^1.0.0", 28848 "rc-util": "^5.15.0" 28849 } 28850 }, 27481 28851 "react": { 27482 28852 "version": "18.2.0", … … 27859 29229 "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" 27860 29230 }, 29231 "resize-observer-polyfill": { 29232 "version": "1.5.1", 29233 "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", 29234 "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" 29235 }, 27861 29236 "resolve": { 27862 29237 "version": "1.22.1", … … 28051 29426 "ajv": "^6.12.5", 28052 29427 "ajv-keywords": "^3.5.2" 29428 } 29429 }, 29430 "scroll-into-view-if-needed": { 29431 "version": "2.2.29", 29432 "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz", 29433 "integrity": "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==", 29434 "requires": { 29435 "compute-scroll-into-view": "^1.0.17" 28053 29436 } 28054 29437 }, … … 28200 29583 "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 28201 29584 }, 29585 "shallowequal": { 29586 "version": "1.1.0", 29587 "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", 29588 "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" 29589 }, 28202 29590 "shebang-command": { 28203 29591 "version": "2.0.0", … … 28373 29761 } 28374 29762 } 29763 }, 29764 "string-convert": { 29765 "version": "0.2.1", 29766 "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", 29767 "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" 28375 29768 }, 28376 29769 "string-length": { … … 28777 30170 "is-number": "^7.0.0" 28778 30171 } 30172 }, 30173 "toggle-selection": { 30174 "version": "1.0.6", 30175 "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", 30176 "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" 28779 30177 }, 28780 30178 "toidentifier": { -
phonelux-frontend/package.json
rffd50db r47f4eaf 16 16 "@testing-library/user-event": "^13.5.0", 17 17 "@tippyjs/react": "^4.2.6", 18 "antd": "^4.23.6", 18 19 "axios": "^0.27.2", 19 20 "jwt-decode": "^3.1.2", -
phonelux-frontend/src/App.js
rffd50db r47f4eaf 12 12 import CompareOffersComponent from "./components/CompareOffersComponent/CompareOffersComponent"; 13 13 import SpecificationsFilterComponent from "./components/FiltersComponents/SpecificationsFilterComponent"; 14 import OfferReportsComponent from "./components/OfferReportsComponent/OfferReportsComponent"; 15 import ScrappersComponent from "./components/ScrappersComponent/ScrappersComponent"; 14 16 15 17 … … 29 31 <Route path="/admin/editoffer/:offerId" element={<EditOfferComponent/>}/> 30 32 <Route path="/compareoffers" element={<CompareOffersComponent/>}/> 33 <Route path="/offerreport/reports" element={<OfferReportsComponent/>}/> 34 <Route path="/scrapperinfo" element={<ScrappersComponent/>}/> 31 35 </Routes> 32 36 </BrowserRouter> -
phonelux-frontend/src/components/EditOfferComponent/EditOfferComponent.js
rffd50db r47f4eaf 17 17 18 18 componentDidMount(){ 19 // if(!localStorage.getItem('token'))20 // {21 // window.location.href = "/"22 // }23 24 // if(this.context.role != 'ADMIN' && this.context.role != 'SUPERADMIN')25 // {26 // window.location.href = "/"27 // }28 29 19 var config = { 30 20 method: 'get', -
phonelux-frontend/src/components/HomepageComponent.js
rffd50db r47f4eaf 220 220 render() { 221 221 // console.log(this.context) 222 //console.log(localStorage.getItem('token'))222 console.log(localStorage.getItem('token')) 223 223 // console.log(this.state) 224 224 return ( -
phonelux-frontend/src/components/LoginRegisterComponents/LoginFormComponent.css
rffd50db r47f4eaf 162 162 background-color: rgb(251, 224, 224); 163 163 } 164 165 .login-with-facebook-image{ 166 width: 40%; 167 } 168 169 .login-with-facebook-image:hover{ 170 cursor: pointer; 171 } 172 173 .login-with-facebook-wrapper{ 174 display: flex; 175 justify-content: center; 176 } -
phonelux-frontend/src/components/LoginRegisterComponents/LoginFormComponent.js
rffd50db r47f4eaf 6 6 import { Link } from 'react-router-dom'; 7 7 import axios from 'axios'; 8 import FacebookLogin from 'react-facebook-login' 8 9 9 10 export class LoginFormComponent extends Component { … … 18 19 } 19 20 } 20 21 changeHandler = (e) =>{ 22 this.setState({[e.target.name] : e.target.value}) 23 } 21 24 22 25 23 submitHandler = (e) => { -
phonelux-frontend/src/components/NavbarComponent/NavbarComponent.js
rffd50db r47f4eaf 12 12 import SupervisorAccountIcon from '@mui/icons-material/SupervisorAccount'; 13 13 import CompareIcon from '@mui/icons-material/Compare'; 14 import BugReportIcon from '@mui/icons-material/BugReport'; 15 import ReportIcon from '@mui/icons-material/Report'; 16 import UpdateIcon from '@mui/icons-material/Update'; 14 17 15 18 export class NavbarComponent extends Component { … … 36 39 <Link style={{color: 'black'}} to={"/management/users"}> 37 40 <SupervisorAccountIcon style={{fontSize: '40px', marginTop: '10px', marginRight: '10px' }} className='navbar-superadmin-icon'/> 41 </Link> 42 </Tippy> : <></> 43 } 44 { 45 localStorage.getItem('token') && this.context.role == 'SUPERADMIN' ? 46 <Tippy placement='bottom' content='Преземање на содржина'> 47 <Link style={{color: 'black'}} to={"/scrapperinfo"}> 48 <UpdateIcon style={{fontSize: '40px', marginTop: '10px', marginRight: '10px' }} className='navbar-superadmin-icon'/> 49 </Link> 50 </Tippy> : <></> 51 } 52 { 53 localStorage.getItem('token') && (this.context.role == 'SUPERADMIN' || this.context.role == 'ADMIN') ? 54 <Tippy placement='bottom' content='Пријавени понуди'> 55 <Link style={{color: 'black'}} to={"/offerreport/reports"}> 56 <BugReportIcon style={{fontSize: '40px', marginTop: '10px', marginRight: '10px' }} className='navbar-offerreports-icon'/> 38 57 </Link> 39 58 </Tippy> : <></> -
phonelux-frontend/src/components/PhoneOfferDetailsComponent/PhoneOfferDetailsComponent.css
rffd50db r47f4eaf 140 140 } 141 141 142 .offerdetails-report-icon{ 143 cursor: pointer; 144 } 142 145 143 146 147 -
phonelux-frontend/src/components/PhoneOfferDetailsComponent/PhoneOfferDetailsComponent.js
rffd50db r47f4eaf 9 9 import VisibilityIcon from '@mui/icons-material/Visibility'; 10 10 import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; 11 import ReportIcon from '@mui/icons-material/Report'; 11 12 12 13 … … 61 62 } 62 63 64 reportOffer = () =>{ 65 alert('Пратена е пријава до администратор за невалидност на спецификациите на понудата!') 66 var config = { 67 method: 'post', 68 url: '/offerreport/'+this.state.offerId+'/'+this.context.userId, 69 headers: { 70 'Authorization': 'Bearer '+localStorage.getItem('token') 71 } 72 }; 73 74 axios(config) 75 .then(function (response) { 76 console.log(JSON.stringify(response.data)); 77 }) 78 .catch(function (error) { 79 console.log(error); 80 }); 81 } 82 63 83 render() { 64 84 console.log(this.state) … … 71 91 { 72 92 localStorage.getItem('token') ? 93 <Tippy placement='bottom' content='Пријави понуда за неточни спецификации'> 94 <ReportIcon onClick={this.reportOffer} className='offerdetails-report-icon' style={{fontSize: '45px'}}/> 95 </Tippy> : <></> 96 } 97 { 98 localStorage.getItem('token') ? 73 99 this.state.showAllSpecs ? 74 100 <Tippy placement='bottom' content='Прикажи ги избраните спецификации'> … … 103 129 104 130 })()} 131 105 132 </div> 106 133 <div className='phone-offer-details-last-updated-wrapper'></div> … … 109 136 <table className='phone-offer-details-table'> 110 137 <thead> 111 <tr><th colSpan={2}>Детали за понудата</th></tr> 138 <tr><th colSpan={2}> 139 Детали за понудата 140 </th></tr> 112 141 </thead> 113 142 <tbody> -
phonelux-frontend/src/components/SuperAdminComponent/SuperAdminComponent.js
rffd50db r47f4eaf 69 69 70 70 componentDidMount(){ 71 // if(!localStorage.getItem('token'))72 // {73 // window.location.href = "/"74 // }75 76 // if(this.context.role != 'SUPERADMIN')77 // {78 // window.location.href = "/"79 // }80 71 this.getUsers() 81 72 } -
phonelux_scrappers/.idea/misc.xml
rffd50db r47f4eaf 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 2 <project version="4"> 3 <component name="ProjectRootManager" version="2" project-jdk-name="Python 3. 8 (phonelux_scrappers) (2)" project-jdk-type="Python SDK" />3 <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (phonelux_scrappers)" project-jdk-type="Python SDK" /> 4 4 </project> -
phonelux_scrappers/.idea/phonelux_scrappers.iml
rffd50db r47f4eaf 5 5 <excludeFolder url="file://$MODULE_DIR$/venv" /> 6 6 </content> 7 <orderEntry type=" inheritedJdk" />7 <orderEntry type="jdk" jdkName="Python 3.9 (phonelux_scrappers)" jdkType="Python SDK" /> 8 8 <orderEntry type="sourceFolder" forTests="false" /> 9 9 </component> -
phonelux_scrappers/outputfile.txt
rffd50db r47f4eaf 1 Samsung Galaxy A132 99903 Apple iPhone 134 474995 Apple iPhone 13 Pro6 626907 Apple iPhone 128 326909 Samsung Galaxy S22 Ultra 5G10 6000011 Apple iPhone 1112 2349013 Samsung Galaxy S22 5G14 4300015 Samsung Galaxy S21 FE16 3380017 Samsung Galaxy A33 5G18 1749019 Apple iPhone 13 Pro Max20 6889021 Samsung Galaxy A3222 1390023 Samsung Galaxy S22+ 5G24 5015025 Apple iPhone 14 Pro26 7189027 Xiaomi 1228 2899929 Samsung Galaxy A53 5G30 2029031 Xiaomi Redmi Note 1132 1199033 Xiaomi Redmi 9A34 649035 Huawei Nova 936 2290037 Samsung Galaxy A1238 950039 Samsung Galaxy Z Flip 440 5840041 Apple iPhone 1442 143 Apple iPhone 13 Mini44 4299045 Samsung Galaxy A52s46 1850047 Xiaomi Redmi 10C48 999049 Apple iPhone SE50 2460051 Samsung Galaxy A03s52 679053 Samsung Galaxy A22 5G54 1170055 Xiaomi Mi 11 Lite56 1850057 Samsung Galaxy A2358 1179059 Apple iPhone 14 Pro Max60 9999961 Samsung Galaxy Z Fold 462 9840063 Samsung Galaxy A0364 849065 Huawei nova Y7066 1369967 Samsung Galaxy Z Flip3 5G68 3899069 Huawei Nova 8i70 1999971 Samsung Galaxy Z Fold 3 5G72 6999073 Xiaomi 11 Lite 5G NE74 2499975 Xiaomi Redmi Note 11 Pro76 1659077 Xiaomi Mi 11T 5G78 2340079 Huawei Nova 9 SE80 2299981 Xiaomi Redmi 982 939983 Huawei nova Y9084 1599985 Apple iPhone SE (2022)86 2829087 Xiaomi Poco X388 1399989 OnePlus Nord N10 5G90 1899991 Samsung Galaxy A5292 1819093 Xiaomi Redmi Note 1094 1399995 Blackview A70 Pro96 739997 Realme C1198 699999 Honor 50 Lite100 11990101 Xiaomi Poco F3102 21500103 Huawei P50 Pro104 58400105 Xiaomi Redmi 9C106 6990107 Xiaomi 12X108 29900109 Blackview A55110 5999111 OnePlus Nord CE112 26999113 Vivo Y72 5G114 18999115 Xiaomi Mi 11T Pro 5G116 33800117 Xiaomi Poco M3118 12290119 Vivo V21 5G120 24999121 Vivo Y33s122 15999123 Samsung Galaxy A02s124 8890125 Motorola Moto G31126 12899127 Xiaomi Mi 11 Lite 5G NE128 25999129 Alcatel 2019G130 2290131 Samsung Galaxy S21+ 5G132 41790133 Xiaomi Redmi Note 10 5G134 13490135 Xiaomi 11T136 31999137 Alcatel 1SE138 6290139 Alcatel 1066D140 1299141 Xiaomi Redmi Note 9142 9990143 Xiaomi Redmi Note 11 Pro+ 5G144 27999145 Blackview A80146 6499147 Motorola Moto G22148 11299149 Xiaomi Poco M3 Pro 5G150 12999151 Xiaomi Redmi Note 9S152 11900153 Blackview A70154 7299155 Xiaomi Redmi 9AT156 6999157 Doogee X95158 5999159 Xiaomi Redmi Note 10 Pro160 15990161 Motorola Edge 20162 30999163 Motorola Moto G60164 16999165 Honor 50166 23400167 Apple iPhone 12 Pro Max168 66500169 Apple iPhone 11 Pro Max170 32690171 Nokia 105 (2017)172 1490173 Samsung Galaxy S21 Ultra 5G174 52290175 Motorola Moto E7 Power176 8999177 Apple iPhone 11 Pro178 27790179 Alcatel 1180 5499181 Xiaomi Poco X3 Pro182 15400183 Xiaomi Redmi Note 9 Pro184 15499185 Blackview A60 Pro186 6299187 Blackview Oscal C20188 5249189 Realme C21Y190 7999191 Vivo Y21192 11899193 Samsung Galaxy A20e194 9699195 Vivo Y21s196 13999197 Nokia 3310198 3399199 Xiaomi Mi 10 Lite 5G200 15990201 Xiaomi Mi Note 10 Lite202 19700203 Samsung Galaxy S21 5G204 38999205 Xiaomi Mi 11 Ultra206 53490207 Motorola Moto G10208 10299209 Alcatel 3026X210 4499211 Samsung Galaxy S20 FE212 22690213 Xiaomi Redmi Note 11S214 19999215 Doogee X96216 7699217 Alcatel 2053D218 2999219 Alcatel 3025X220 3999221 Doogee X93222 5999223 Vivo Y20s224 12499225 Infinix Hot 11226 10499227 Infinix Smart 6228 7999229 Panasonic KX-TU160230 3999231 Xiaomi 12 Pro232 54150233 Xiaomi Mi 10T Pro 5G234 29900235 Xiaomi Poco X4 Pro 5G236 17200237 Apple iPhone 12 Pro238 61590239 Google Pixel 6 Pro240 61500241 Samsung Galaxy Note 20242 36900243 Xiaomi Poco M4 Pro 5G244 15999245 OnePlus 10 Pro 5G246 52290247 Wiko View248 5990249 Samsung Galaxy A72250 23300251 Alcatel 2003D252 2199253 Xiaomi Redmi Note 10 Pro Max254 16490255 Trevi Max 10256 1599257 Honor X8258 16499259 Nokia 6310260 5490261 Xiaomi 11T Pro262 47999263 Samsung Galaxy A02264 8000265 Samsung Galaxy A40266 11999267 Motorola Moto G71268 18999269 Samsung Galaxy Note 20 Ultra 5G270 50390271 Samsung Galaxy A73 5G272 27000273 Xiaomi Redmi Note 10S274 14999275 Blackview A60276 4999277 Blackview A80 Plus278 8999279 Realme C21280 8999281 Motorola Moto G51282 14999283 Xiaomi Mi 10T Lite 5G284 15390285 OnePlus 9 Pro286 46200287 Cubot P30288 9999289 Cubot Note 20290 8999291 Motorola Moto G30292 13999293 Asus ROG Phone 5294 46100295 Tesla Smartphone 3.4296 4999297 Oppo F11 Pro298 16600299 Honor View 20300 36800301 Honor 70302 32999303 Realme 8i304 15999305 OnePlus 9306 30800307 Samsung Galaxy M12308 9500309 Samsung Galaxy A31310 16999311 Xiaomi Redmi 9i312 8890313 OnePlus 7T Pro McLaren Edition314 36900315 OnePlus 7T316 27700317 Oppo A9318 16600319 Nokia 8110 4G320 4300321 Blackberry Porsche Design P9981322 19000323 Asus ROG Phone 2324 32000325 Xiaomi Redmi Note 9T 5G326 12290327 Motorola Edge 20 Pro328 44999329 Xiaomi Poco X3 GT330 17200331 Nokia 105 (2019)332 1999333 Apple iPhone 12 Mini334 34999335 Samsung Galaxy Z Fold 2336 141499337 Samsung Galaxy M32338 14100339 Alcatel 1S340 6390341 Doogee X95 Pro342 7399343 Doogee S58 Pro344 12499345 Motorola Moto G100346 30999347 Motorola Moto G200348 30999349 Realme 9i350 16699351 Realme 9 Pro+352 27999353 Realme GT Master354 20300355 Alcatel 1C356 4499357 Trevi Flex 50 GT358 2199359 Huawei Honor 8X Max360 12300361 Huawei Honor 9X Lite362 11000363 Oppo A94 5G364 15390365 MeanIT Veteran I366 1599367 MeanIT Senior Flip XL368 3399369 Denver B242370 2999371 Asus ROG Phone 3372 36900373 Huawei Y Max374 12300375 Apple iPhone X376 15990377 Xiaomi Redmi Note 11T 5G378 18500379 Motorola G60380 17999381 OnePlus 8 Pro382 40000383 Samsung Galaxy M52 5G384 21500385 Xiaomi Mi 12 Pro 5G386 54100387 Alcatel 1066G388 1190389 Google Pixel 6390 40000391 Wiko View Max392 7990393 Xiaomi Black Shark 4394 29990395 Tcl 20L+396 15999397 Xiaomi Poco F4 GT398 47999399 Samsung Galaxy A51400 18999401 Samsung Galaxy A50402 18999403 Xiaomi Mi A2 Lite404 8999405 Xiaomi Mi Play406 9999407 Xiaomi Mi 6408 9999409 Xiaomi Mi Max 2410 6999411 Xiaomi Mi A3412 8999413 Samsung Galaxy A30s414 13999415 Samsung Galaxy A41416 16999417 Alcatel Pixi 4 Power Plus418 5999419 Honor X7420 13999421 Energizer Energy E20422 1999423 Energizer Energy E241S424 2299425 Energizer Hardcase H240S426 3999427 Energizer Power Max P550S428 4999429 Huawei Mate 10 Lite430 9999431 Samsung Galaxy M02s432 9500433 Xiaomi Mi 10T 5G434 24500435 Xiaomi Redmi 8A436 7400437 Huawei P30 Pro438 29500439 Huawei P40 Lite E440 9200441 Apple iPhone XS442 17890443 Apple iPhone XS Max444 21590445 Nokia C21446 8999447 Alcatel 1S (2021)448 8999449 Huawei P50 Pocket450 76900451 CAT B26452 5999453 Cubot J9454 5299455 Samsung Galaxy A21s456 11199457 Xiaomi Mi A2458 13799459 Alcatel 1V460 4399461 Trevi Phablet 5Q2462 4599463 Energizer Energy E10464 1299465 Huawei P20466 24999467 Honor 9 Lite468 7999469 Huawei Honor 8X470 16999471 Honor 10 Lite472 8499473 Wiko Power U20474 8999475 Wiko Y62476 6999477 Vivax Pro M1478 4499479 Vivax Fun S10480 3999481 Vivax Fun S20482 4999483 Vivax Point X2484 5999485 Vivax Fly 5 Lite486 7499487 Vivax Fly V1488 8999489 Vivax Point X502490 4499491 Vivax Point X1492 6999493 Vivax Fun S1494 2999495 Oppo A15s496 8999497 Oppo Reno4 Z 5G498 18999499 Oppo Reno5 5G500 24999501 Oppo Reno4 Lite502 15999503 Oppo Find X5 Lite504 24590505 Denver B183506 1499507 Noa N2508 7499509 Noa Sprint 4G510 5499511 Samsung Galaxy J7512 8999513 Manta MS1701514 1099515 Huawei P10 Lite516 11999517 Xiaomi Redmi Note 10T 5G518 12300519 Nokia 6300 4G520 4000521 Tcl 306522 9999523 Oppo Find X3 Lite524 16000525 Wiko Lenny 5526 4290527 Doro 2404528 4499529 AllCall Smooth 4G530 5499531 Realme C25Y532 10999533 Motorola Moto G41534 16999535 Honor Magic4 Lite536 21999537 Huawei Honor 7A538 5999539 Honor 20 Lite540 11299541 Panasonic KX-TU155542 4699543 Vivax Fly 6544 5999545 Tesla Feature 3546 1599547 Noa Fresh 4G548 2999549 Samsung Galaxy F12550 9200551 Nokia 106552 1999553 OnePlus Nord554 22999555 Infinix Hot 12i556 9999557 Doro 1370558 4999559 Apple iPhone XR560 17290561 Doogee X96 Pro562 8799563 Samsung Galaxy F62564 18400565 OnePlus 9R566 27700567 Alcatel 3080G568 4499569 Motorola Moto E20570 8999571 AllCall Brother 4G572 5499573 Realme 8574 14999575 Huawei Honor 7S576 7599577 Motorola Moto G50578 16999579 Nokia 110580 2299581 Motorola Edge 30582 31999583 Realme 9 Pro584 22499585 Nokia 8586 14999587 OnePlus Nord N100588 10499 -
phonelux_scrappers/phones_image_setter.py
rffd50db r47f4eaf 13 13 offers = list(json.loads(requests.get('http://localhost:8080/phones/offers/' + phone_id).text)) 14 14 15 offers = list(filter(lambda offer: offer['image_url'] is not None, offers)) 15 # remove mobitech condition 16 offers = list(filter(lambda offer: offer['image_url'] is not None and 'mobitech' not in offer['image_url'] 17 , offers)) 16 18 17 19 image_url = None 18 20 21 if len(offers) > 1: 22 image_url = offers[1]['image_url'] 23 19 24 if len(offers) > 0: 20 25 image_url = offers[0]['image_url'] 26 27 # print('phone :'+str(phone)) 28 # print(image_url) 29 # print('------------------------------') 21 30 22 31 phone['image_url'] = image_url -
phonelux_scrappers/phones_model_setter.py
rffd50db r47f4eaf 23 23 break 24 24 if not flag: 25 # requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(offer['id'])) 26 print('delete offer id '+str(offer['id'])) 25 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(offer['id'])) -
phonelux_scrappers/scrappers/a1_scrapper.py
rffd50db r47f4eaf 1 import traceback 1 2 import unicodedata 2 3 from datetime import datetime … … 18 19 is_validated = False 19 20 20 # A1 phone offers that are already in database 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 21 30 22 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/a1').text)) 31 try: 32 # A1 phone offers that are already in database 33 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/a1').text)) 23 34 24 database_offers = []35 database_offers = [] 25 36 26 for offer in offers:27 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],28 offer['ram_memory'],29 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],30 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],31 offer['image_url'],32 offer['offer_url'], offer['last_updated'], offer['is_validated'],33 offer['offer_description'],34 offer['offer_shop_code'])35 database_offers.append(phoneOffer)37 for offer in offers: 38 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 39 offer['ram_memory'], 40 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 41 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 42 offer['image_url'], 43 offer['offer_url'], offer['last_updated'], offer['is_validated'], 44 offer['offer_description'], 45 offer['offer_shop_code']) 46 database_offers.append(phoneOffer) 36 47 37 a1_url = 'https://www.a1.mk/webshop/mk/phones'48 a1_url = 'https://www.a1.mk/webshop/mk/phones' 38 49 39 response1 = requests.get(a1_url)40 soup1 = BeautifulSoup(response1.content, 'html.parser')50 response1 = requests.get(a1_url) 51 soup1 = BeautifulSoup(response1.content, 'html.parser') 41 52 42 phones = soup1.find('main', {'class', 'gsm-advisor-grid phones'}).find('div', {'class', 'd-flex'}) \43 .find_all('div', {'class', 'dvc-idtfr by4'})53 phones = soup1.find('main', {'class', 'gsm-advisor-grid phones'}).find('div', {'class', 'd-flex'}) \ 54 .find_all('div', {'class', 'dvc-idtfr by4'}) 44 55 45 new_offers = []56 new_offers = [] 46 57 47 for phone in phones:48 brand = phone.get('data-brand').strip()49 offer_name = brand + " " + phone.get('data-model').strip()58 for phone in phones: 59 brand = phone.get('data-brand').strip() 60 offer_name = brand + " " + phone.get('data-model').strip() 50 61 51 # if brand not in offer_name:52 # offer_name = brand+" "+offer_name62 # if brand not in offer_name: 63 # offer_name = brand+" "+offer_name 53 64 54 offer_shop_code = phone.get('data-productid').strip()55 offer_url = phone.find('a', {'class', 'device-link'}).get('href')56 image_url = phone.get('data-image')65 offer_shop_code = phone.get('data-productid').strip() 66 offer_url = phone.find('a', {'class', 'device-link'}).get('href') 67 image_url = phone.get('data-image') 57 68 58 response2 = requests.get(offer_url)59 soup2 = BeautifulSoup(response2.content, 'html.parser')69 response2 = requests.get(offer_url) 70 soup2 = BeautifulSoup(response2.content, 'html.parser') 60 71 61 temp_prices = soup2.find('div', {'class': 'ured-tabs-content'}) \62 .find('div', {'class': 'cenovnik-secondary d-flex justify-content-between'}).find_all('div')72 temp_prices = soup2.find('div', {'class': 'ured-tabs-content'}) \ 73 .find('div', {'class': 'cenovnik-secondary d-flex justify-content-between'}).find_all('div') 63 74 64 # offer price65 price = None66 for temp_price in temp_prices:67 if 'Цена само за уред' in temp_price.get_text().strip():68 price = int(temp_price.get_text().replace('Цена само за уред', '')69 .replace('Одбери', '').replace('денари', '').replace('.', '').strip())75 # offer price 76 price = None 77 for temp_price in temp_prices: 78 if 'Цена само за уред' in temp_price.get_text().strip(): 79 price = int(temp_price.get_text().replace('Цена само за уред', '') 80 .replace('Одбери', '').replace('денари', '').replace('.', '').strip()) 70 81 71 colors_section = soup2.find('div', {'id': 'hero'}).find('div', {'class': 'widget'}).find_all('label')82 colors_section = soup2.find('div', {'id': 'hero'}).find('div', {'class': 'widget'}).find_all('label') 72 83 73 temp_colors = []74 for color_section in colors_section:75 temp_colors.append(color_section.get('data-content'))84 temp_colors = [] 85 for color_section in colors_section: 86 temp_colors.append(color_section.get('data-content')) 76 87 77 color = ','.join(temp_colors) # colors available for the offer88 color = ','.join(temp_colors) # colors available for the offer 78 89 79 phone_description = soup2.find('div', {'class': 'desc section'}).find('p').get_text().strip()90 phone_description = soup2.find('div', {'class': 'desc section'}).find('p').get_text().strip() 80 91 81 table_rows = soup2.find('table', {'class': 'table karakteristiki'}).find_all('tr')92 table_rows = soup2.find('table', {'class': 'table karakteristiki'}).find_all('tr') 82 93 83 back_camera = None84 operating_system = None85 cpu = None86 rom_memory = None87 ram_memory = None88 battery = None89 front_camera = None90 chipset = None91 offer_description = None94 back_camera = None 95 operating_system = None 96 cpu = None 97 rom_memory = None 98 ram_memory = None 99 battery = None 100 front_camera = None 101 chipset = None 102 offer_description = None 92 103 93 for row in table_rows:94 if 'Камера' in row.get_text().strip():95 back_camera = row.get_text().replace('Камера', '').strip()104 for row in table_rows: 105 if 'Камера' in row.get_text().strip(): 106 back_camera = row.get_text().replace('Камера', '').strip() 96 107 97 if 'Оперативен систем' in row.get_text().strip():98 operating_system = row.get_text().replace('Оперативен систем', '').strip()108 if 'Оперативен систем' in row.get_text().strip(): 109 operating_system = row.get_text().replace('Оперативен систем', '').strip() 99 110 100 if 'CPU' in row.get_text().strip():101 cpu = row.get_text().replace('CPU', '').strip()111 if 'CPU' in row.get_text().strip(): 112 cpu = row.get_text().replace('CPU', '').strip() 102 113 103 if 'Вградена меморија' in row.get_text().strip():104 rom_memory = row.get_text().replace('Вградена меморија', '').strip()114 if 'Вградена меморија' in row.get_text().strip(): 115 rom_memory = row.get_text().replace('Вградена меморија', '').strip() 105 116 106 if 'RAM меморија' in row.get_text().strip():107 ram_memory = row.get_text().replace('RAM меморија', '').strip()117 if 'RAM меморија' in row.get_text().strip(): 118 ram_memory = row.get_text().replace('RAM меморија', '').strip() 108 119 109 if 'Батерија' in row.get_text().strip():110 battery = row.get_text().replace('Батерија', '').strip()120 if 'Батерија' in row.get_text().strip(): 121 battery = row.get_text().replace('Батерија', '').strip() 111 122 112 if 'Предна камера' in row.get_text().strip():113 front_camera = row.get_text().replace('Предна камера', '').strip()123 if 'Предна камера' in row.get_text().strip(): 124 front_camera = row.get_text().replace('Предна камера', '').strip() 114 125 115 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 116 color, front_camera, back_camera, chipset, battery, operating_system, cpu, image_url, 117 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 126 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 127 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 128 image_url, 129 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 118 130 119 for new_offer in new_offers: 120 flag = False 121 flag_price = False 122 offer_id = None 131 for new_offer in new_offers: 132 flag = False 133 flag_price = False 134 offer_id = None 135 136 for old_offer in database_offers: 137 138 if new_offer.offer_shop_code == old_offer.offer_shop_code: 139 flag = True 140 if new_offer.price != old_offer.price: 141 flag_price = True 142 offer_id = old_offer.offer_id 143 144 if flag: 145 # print('ALREADY IN DATABASE') 146 # print(new_offer) 147 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 148 if flag_price: 149 print('PRICE CHANGED!') # CHANGE PRICE 150 print('offer id: ' + str(offer_id)) 151 headers = {'Content-type': 'application/json'} 152 requests.put( 153 'http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 154 headers=headers) 155 else: 156 print('ADDED') # ADD OFFER 157 print(new_offer) 158 headers = {'Content-type': 'application/json'} 159 requests.post('http://localhost:8080/phoneoffer/addoffer', headers=headers, 160 data=json.dumps(new_offer.__dict__, 161 default=str)) 162 163 print('------------------------------------') 123 164 124 165 for old_offer in database_offers: 166 flag = False 167 for new_offer in new_offers: 168 if old_offer.offer_shop_code == new_offer.offer_shop_code: 169 flag = True 125 170 126 if new_offer.offer_shop_code == old_offer.offer_shop_code: 127 flag = True 128 if new_offer.price != old_offer.price: 129 flag_price = True 130 offer_id = old_offer.offer_id 131 132 if flag: 133 # print('ALREADY IN DATABASE') 134 # print(new_offer) 135 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 136 if flag_price: 137 print('PRICE CHANGED!') # CHANGE PRICE 138 print('offer id: ' + str(offer_id)) 139 headers = {'Content-type': 'application/json'} 140 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 141 headers=headers) 142 else: 143 print('ADDED') # ADD OFFER 144 print(new_offer) 145 headers = {'Content-type': 'application/json'} 146 requests.post('http://localhost:8080/phoneoffer/addoffer', headers=headers, data=json.dumps(new_offer.__dict__, 147 default=str)) 148 149 print('------------------------------------') 150 151 for old_offer in database_offers: 152 flag = False 153 for new_offer in new_offers: 154 if old_offer.offer_shop_code == new_offer.offer_shop_code: 155 flag = True 156 157 if not flag: 158 print('OFFER DELETED') 159 print(old_offer) 160 # DELETE OFFER 161 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 171 if not flag: 172 print('OFFER DELETED') 173 print(old_offer) 174 # DELETE OFFER 175 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 176 except Exception: 177 traceback.print_exc() 178 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 179 ' VALUES (%s, %s, %s);' 180 insert_value = (offer_shop, last_updated, 'failed') 181 cur.execute(insert_script, insert_value) 182 db_connection.commit() 183 cur.close() 184 db_connection.close() 185 else: 186 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 187 ' VALUES (%s, %s, %s);' 188 insert_value = (offer_shop, last_updated, 'success') 189 cur.execute(insert_script, insert_value) 190 db_connection.commit() 191 cur.close() 192 db_connection.close() -
phonelux_scrappers/scrappers/akcija_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 from datetime import datetime 3 4 … … 18 19 is_validated = False 19 20 20 # Akcija phone offers that are already in database 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 21 30 22 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/akcija').text)) 31 try: 32 # Akcija phone offers that are already in database 33 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/akcija').text)) 23 34 24 database_offers = []35 database_offers = [] 25 36 26 for offer in offers:27 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],28 offer['ram_memory'],29 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],30 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],31 offer['image_url'],32 offer['offer_url'], offer['last_updated'], offer['is_validated'],33 offer['offer_description'],34 offer['offer_shop_code'])35 database_offers.append(phoneOffer)37 for offer in offers: 38 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 39 offer['ram_memory'], 40 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 41 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 42 offer['image_url'], 43 offer['offer_url'], offer['last_updated'], offer['is_validated'], 44 offer['offer_description'], 45 offer['offer_shop_code']) 46 database_offers.append(phoneOffer) 36 47 37 new_offers = []48 new_offers = [] 38 49 39 i = 040 while i <= 20:41 akcija_url = "https://akcija.com.mk/listing/" + str(i) + "?category=mobilnitelefoni"42 response1 = requests.get(akcija_url)43 response1.encoding = 'utf-8'44 soup1 = BeautifulSoup(response1.text, 'html.parser')50 i = 0 51 while i <= 20: 52 akcija_url = "https://akcija.com.mk/listing/" + str(i) + "?category=mobilnitelefoni" 53 response1 = requests.get(akcija_url) 54 response1.encoding = 'utf-8' 55 soup1 = BeautifulSoup(response1.text, 'html.parser') 45 56 46 phones = soup1.find_all('div', {'class', 'product-item__body pb-xl-2'})57 phones = soup1.find_all('div', {'class', 'product-item__body pb-xl-2'}) 47 58 48 for phone in phones:49 offer_name = phone.find('h5', {'class': 'mb-1 product-item__title'}).find('a') \50 .get_text().replace('Паметен телефон', '').strip()51 brand = offer_name.split(' ')[0]59 for phone in phones: 60 offer_name = phone.find('h5', {'class': 'mb-1 product-item__title'}).find('a') \ 61 .get_text().replace('Паметен телефон', '').strip() 62 brand = offer_name.split(' ')[0] 52 63 53 if brand not in offer_name:54 offer_name = brand + " " + offer_name64 if brand not in offer_name: 65 offer_name = brand + " " + offer_name 55 66 56 offer_url = phone.find('h5', {'class': 'mb-1 product-item__title'}).find('a').get('href')57 image_url = phone.find('div', {'class', 'mb-2'}).find('img').get('src')58 price = int(phone.find('div', {'class', 'flex-center-between mb-1 pt-xl-2'}) \59 .find('ins').get_text().split(' ')[0].strip())67 offer_url = phone.find('h5', {'class': 'mb-1 product-item__title'}).find('a').get('href') 68 image_url = phone.find('div', {'class', 'mb-2'}).find('img').get('src') 69 price = int(phone.find('div', {'class', 'flex-center-between mb-1 pt-xl-2'}) \ 70 .find('ins').get_text().split(' ')[0].strip()) 60 71 61 response2 = requests.get(offer_url)62 response2.encoding = 'utf-8'63 soup2 = BeautifulSoup(response2.text, 'html.parser')72 response2 = requests.get(offer_url) 73 response2.encoding = 'utf-8' 74 soup2 = BeautifulSoup(response2.text, 'html.parser') 64 75 65 back_camera = None66 operating_system = None67 chipset = None68 battery = None69 ram_memory = None70 rom_memory = None71 cpu = None72 front_camera = None73 color = None74 offer_shop_code = None76 back_camera = None 77 operating_system = None 78 chipset = None 79 battery = None 80 ram_memory = None 81 rom_memory = None 82 cpu = None 83 front_camera = None 84 color = None 85 offer_shop_code = None 75 86 76 specifications = soup2.find('main', {'id': 'content'}) \77 .find_all('div', {'class', 'container'})[1].find('div', {'class', 'mb-14'}) \78 .find('div', {'class', 'col-md-6 col-lg-4 col-xl-4 mb-md-6 mb-lg-0'}).find_all('p')87 specifications = soup2.find('main', {'id': 'content'}) \ 88 .find_all('div', {'class', 'container'})[1].find('div', {'class', 'mb-14'}) \ 89 .find('div', {'class', 'col-md-6 col-lg-4 col-xl-4 mb-md-6 mb-lg-0'}).find_all('p') 79 90 80 offer_description = ''81 for specification in specifications:82 if 'Код за нарачка' in str(specification.get_text(separator='\n').replace('NBSP', '').strip()):83 continue84 offer_description += unicodedata.normalize('NFKD',85 str(specification.get_text(separator='\n').strip())) + "\n"91 offer_description = '' 92 for specification in specifications: 93 if 'Код за нарачка' in str(specification.get_text(separator='\n').replace('NBSP', '').strip()): 94 continue 95 offer_description += unicodedata.normalize('NFKD', 96 str(specification.get_text(separator='\n').strip())) + "\n" 86 97 87 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory,88 color, front_camera, back_camera, chipset, battery, operating_system, cpu,89 image_url,90 offer_url, last_updated, is_validated, offer_description, offer_shop_code))91 i += 2098 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 99 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 100 image_url, 101 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 102 i += 20 92 103 93 for new_offer in new_offers: 94 flag = False 95 flag_price = False 96 offer_id = None 104 for new_offer in new_offers: 105 flag = False 106 flag_price = False 107 offer_id = None 108 109 for old_offer in database_offers: 110 111 if new_offer.offer_name == old_offer.offer_name: 112 flag = True 113 if new_offer.price != old_offer.price: 114 flag_price = True 115 offer_id = old_offer.offer_id 116 117 if flag: 118 # print('ALREADY IN DATABASE') 119 # print(new_offer) 120 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 121 if flag_price: 122 print('PRICE CHANGED!') # CHANGE PRICE 123 print('offer id: ' + str(offer_id)) 124 headers = {'Content-type': 'application/json'} 125 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 126 headers=headers) 127 else: 128 print('ADDED') # ADD OFFER 129 print(new_offer) 130 headers = {'Content-type': 'application/json'} 131 requests.post('http://localhost:8080/phoneoffer/addoffer', 132 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 133 134 print('------------------------------------') 97 135 98 136 for old_offer in database_offers: 137 flag = False 138 for new_offer in new_offers: 139 if old_offer.offer_name == new_offer.offer_name: 140 flag = True 99 141 100 if new_offer.offer_name == old_offer.offer_name: 101 flag = True 102 if new_offer.price != old_offer.price: 103 flag_price = True 104 offer_id = old_offer.offer_id 142 if not flag: 143 print('OFFER DELETED') 144 print(old_offer) 145 # DELETE OFFER 146 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 147 except Exception: 148 traceback.print_exc() 149 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 150 ' VALUES (%s, %s, %s);' 151 insert_value = (offer_shop, last_updated, 'failed') 152 cur.execute(insert_script, insert_value) 153 db_connection.commit() 154 cur.close() 155 db_connection.close() 156 else: 157 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 158 ' VALUES (%s, %s, %s);' 159 insert_value = (offer_shop, last_updated, 'success') 160 cur.execute(insert_script, insert_value) 161 db_connection.commit() 162 cur.close() 163 db_connection.close() 105 164 106 if flag:107 # print('ALREADY IN DATABASE')108 # print(new_offer)109 # if it's already in database, check PRICE and if it's changed, change it !!!!!!110 if flag_price:111 print('PRICE CHANGED!') # CHANGE PRICE112 print('offer id: ' + str(offer_id))113 headers = {'Content-type': 'application/json'}114 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price),115 headers=headers)116 else:117 print('ADDED') # ADD OFFER118 print(new_offer)119 headers = {'Content-type': 'application/json'}120 requests.post('http://localhost:8080/phoneoffer/addoffer',121 headers=headers, data=json.dumps(new_offer.__dict__, default=str))122 123 print('------------------------------------')124 125 for old_offer in database_offers:126 flag = False127 for new_offer in new_offers:128 if old_offer.offer_name == new_offer.offer_name:129 flag = True130 131 if not flag:132 print('OFFER DELETED')133 print(old_offer)134 # DELETE OFFER135 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) -
phonelux_scrappers/scrappers/handy_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 20 21 is_validated = False 21 22 22 # Handy phone offers that are already in database 23 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/handy').text)) 23 # Call to read the configuration file and connect to database 24 cinfo = config_read.get_databaseconfig("../postgresdb.config") 25 db_connection = psycopg2.connect( 26 database=cinfo[0], 27 host=cinfo[1], 28 user=cinfo[2], 29 password=cinfo[3] 30 ) 31 cur = db_connection.cursor() 24 32 25 database_offers = [] 33 try: 34 # Handy phone offers that are already in database 35 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/handy').text)) 26 36 27 for offer in offers: 28 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 29 offer['ram_memory'], 30 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 31 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 32 offer['image_url'], 33 offer['offer_url'], offer['last_updated'], offer['is_validated'], 34 offer['offer_description'], 35 offer['offer_shop_code']) 36 database_offers.append(phoneOffer) 37 database_offers = [] 37 38 38 new_offers = [] 39 for offer in offers: 40 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 41 offer['ram_memory'], 42 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 43 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 44 offer['image_url'], 45 offer['offer_url'], offer['last_updated'], offer['is_validated'], 46 offer['offer_description'], 47 offer['offer_shop_code']) 48 database_offers.append(phoneOffer) 39 49 40 handy_url = 'https://www.handy.mk/telefoni?page=6' 50 new_offers = [] 41 51 42 response1 = requests.get(handy_url) 43 soup1 = BeautifulSoup(response1.content, 'html.parser') 52 handy_url = 'https://www.handy.mk/telefoni?page=6' 44 53 45 phones = soup1.find_all('li', {'data-hook': 'product-list-grid-item'}) 54 response1 = requests.get(handy_url) 55 soup1 = BeautifulSoup(response1.content, 'html.parser') 46 56 47 for phone in phones: 48 offer_url = phone.find('a').get('href') 49 offer_name = phone.find('div', {'data-hook': 'not-image-container'})\ 50 .find('h3', {'data-hook': 'product-item-name'}).get_text().strip() 51 brand = offer_name.split(' ')[0].capitalize() 52 price = int(float(phone.find('div', {'data-hook': 'not-image-container'}).find('div', {'data-hook': "product-item-product-details"})\ 53 .find('span', {'data-hook': 'product-item-price-to-pay'}).get_text().strip().replace('ден', '').replace('.', '').replace(',', '.'))) 57 phones = soup1.find_all('li', {'data-hook': 'product-list-grid-item'}) 54 58 55 response2 = requests.get(offer_url) 56 soup2 = BeautifulSoup(response2.text, 'html.parser') 59 for phone in phones: 60 offer_url = phone.find('a').get('href') 61 offer_name = phone.find('div', {'data-hook': 'not-image-container'})\ 62 .find('h3', {'data-hook': 'product-item-name'}).get_text().strip() 63 brand = offer_name.split(' ')[0].capitalize() 64 price = int(float(phone.find('div', {'data-hook': 'not-image-container'}).find('div', {'data-hook': "product-item-product-details"})\ 65 .find('span', {'data-hook': 'product-item-price-to-pay'}).get_text().strip().replace('ден', '').replace('.', '').replace(',', '.'))) 57 66 58 back_camera = None 59 operating_system = None 60 chipset = None 61 battery = None 62 ram_memory = None 63 rom_memory = None 64 cpu = None 65 front_camera = None 66 offer_shop_code = None 67 color = None 68 image_url = None 67 response2 = requests.get(offer_url) 68 soup2 = BeautifulSoup(response2.text, 'html.parser') 69 69 70 color_section = soup2.find('section', {'data-hook': 'product-colors-title-section'}) 71 if color_section is not None: 72 temp_colors = color_section.find('fieldset', {'class': 'ColorPickerbase3548966286__container'})\ 73 .find_all('input', {'type': 'radio'}) 74 colors_list = [] 75 for temp_color in temp_colors: 76 colors_list.append(temp_color.get('aria-label')) 77 color = ','.join(colors_list) 70 back_camera = None 71 operating_system = None 72 chipset = None 73 battery = None 74 ram_memory = None 75 rom_memory = None 76 cpu = None 77 front_camera = None 78 offer_shop_code = None 79 color = None 80 image_url = None 78 81 79 rows = soup2.find('div', {'data-hook': 'info-section-description'}).find_all('li') 82 color_section = soup2.find('section', {'data-hook': 'product-colors-title-section'}) 83 if color_section is not None: 84 temp_colors = color_section.find('fieldset', {'class': 'ColorPickerbase3548966286__container'})\ 85 .find_all('input', {'type': 'radio'}) 86 colors_list = [] 87 for temp_color in temp_colors: 88 colors_list.append(temp_color.get('aria-label')) 89 color = ','.join(colors_list) 80 90 81 if len(rows) == 0: 82 rows = soup2.find('div', {'data-hook': 'info-section-description'}).find_all('tr') 91 rows = soup2.find('div', {'data-hook': 'info-section-description'}).find_all('li') 83 92 84 specifications = [] 93 if len(rows) == 0: 94 rows = soup2.find('div', {'data-hook': 'info-section-description'}).find_all('tr') 85 95 86 for row in rows: 87 specifications.append(unicodedata.normalize('NFKD', row.get_text().strip())) 96 specifications = [] 88 97 89 offer_description = '\n'.join(specifications) 98 for row in rows: 99 specifications.append(unicodedata.normalize('NFKD', row.get_text().strip())) 90 100 91 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 92 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 93 image_url, 94 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 101 offer_description = '\n'.join(specifications) 95 102 96 for new_offer in new_offers: 97 flag = False 98 flag_price = False 99 offer_id = None 103 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 104 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 105 image_url, 106 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 107 108 for new_offer in new_offers: 109 flag = False 110 flag_price = False 111 offer_id = None 112 113 for old_offer in database_offers: 114 115 if new_offer.offer_name == old_offer.offer_name: 116 flag = True 117 if new_offer.price != old_offer.price: 118 flag_price = True 119 offer_id = old_offer.offer_id 120 121 if flag: 122 # print('ALREADY IN DATABASE') 123 # print(new_offer) 124 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 125 if flag_price: 126 print('PRICE CHANGED!') # CHANGE PRICE 127 print('offer id: ' + str(offer_id)) 128 headers = {'Content-type': 'application/json'} 129 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 130 headers=headers) 131 else: 132 print('ADDED') # ADD OFFER 133 print(new_offer) 134 headers = {'Content-type': 'application/json'} 135 requests.post('http://localhost:8080/phoneoffer/addoffer', 136 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 137 138 print('------------------------------------') 100 139 101 140 for old_offer in database_offers: 141 flag = False 142 for new_offer in new_offers: 143 if old_offer.offer_name == new_offer.offer_name: 144 flag = True 102 145 103 if new_offer.offer_name == old_offer.offer_name: 104 flag = True 105 if new_offer.price != old_offer.price: 106 flag_price = True 107 offer_id = old_offer.offer_id 108 109 if flag: 110 # print('ALREADY IN DATABASE') 111 # print(new_offer) 112 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 113 if flag_price: 114 print('PRICE CHANGED!') # CHANGE PRICE 115 print('offer id: ' + str(offer_id)) 116 headers = {'Content-type': 'application/json'} 117 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 118 headers=headers) 119 else: 120 print('ADDED') # ADD OFFER 121 print(new_offer) 122 headers = {'Content-type': 'application/json'} 123 requests.post('http://localhost:8080/phoneoffer/addoffer', 124 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 125 126 print('------------------------------------') 127 128 for old_offer in database_offers: 129 flag = False 130 for new_offer in new_offers: 131 if old_offer.offer_name == new_offer.offer_name: 132 flag = True 133 134 if not flag: 135 print('OFFER DELETED') 136 print(old_offer) 137 # DELETE OFFER 138 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 146 if not flag: 147 print('OFFER DELETED') 148 print(old_offer) 149 # DELETE OFFER 150 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 151 except Exception: 152 traceback.print_exc() 153 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 154 ' VALUES (%s, %s, %s);' 155 insert_value = (offer_shop, last_updated, 'failed') 156 cur.execute(insert_script, insert_value) 157 db_connection.commit() 158 cur.close() 159 db_connection.close() 160 else: 161 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 162 ' VALUES (%s, %s, %s);' 163 insert_value = (offer_shop, last_updated, 'success') 164 cur.execute(insert_script, insert_value) 165 db_connection.commit() 166 cur.close() 167 db_connection.close() 139 168 140 169 170 -
phonelux_scrappers/scrappers/ledikom_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 19 20 is_validated = False 20 21 21 # Ledikom phone offers that are already in database 22 23 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/ledikom').text)) 24 25 database_offers = [] 26 27 for offer in offers: 28 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 29 offer['ram_memory'], 30 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 31 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 32 offer['image_url'], 33 offer['offer_url'], offer['last_updated'], offer['is_validated'], 34 offer['offer_description'], 35 offer['offer_shop_code']) 36 database_offers.append(phoneOffer) 37 38 new_offers = [] 39 40 ledikom_phone_urls = [ 41 'https://ledikom.mk/c/416/uredi/apple/iphone?limit=96', 42 'https://ledikom.mk/c/421/uredi/samsung/telefoni?limit=96', 43 'https://ledikom.mk/c/424/mobilni-telefoni/xiaomi/telefoni?limit=96', 44 'https://ledikom.mk/c/430/uredi/huawei/telefoni?limit=96', 45 'https://ledikom.mk/c/441/uredi/oneplus/telefoni?limit=96', 46 'https://ledikom.mk/c/413/uredi/google/telefoni?limit=96', 47 'https://ledikom.mk/c/411/uredi/honor/telefoni?limit=96', 48 'https://ledikom.mk/c/460/uredi/nokia/telefoni?limit=96', 49 'https://ledikom.mk/c/461/uredi/asus/telefoni?limit=96', 50 'https://ledikom.mk/c/488/proizvodi/oppo/telefoni?limit=96' 51 ] 52 53 for ledikom_url in ledikom_phone_urls: 54 55 # selenium is used because of the dynamic content of the page 56 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 57 driver1.get(ledikom_url) 58 ledikom_html = driver1.page_source 59 60 # closing the driver so the safari instance can pair with another webdriver session 61 driver1.close() 62 63 soup1 = BeautifulSoup(ledikom_html, 'html.parser') 64 65 phones = soup1.find('div', {'id': 'content'}) \ 66 .find('div', {'class': 'container'}).find('div', {'class': 'row'}).find('div', {'class': 'item-display'}) \ 67 .find_all('div', {'class': 'item-in-grid'}) 68 69 if len(phones) == 0: 70 continue 71 72 for phone in phones: 73 offer_url = 'https://ledikom.mk' + phone.find('a').get('href') 74 image_url = phone.find('a').find('img').get('src') 75 temp_offer_name = phone.find('div', {'class': 'item-name'}).find('a').get_text().strip() 76 offer_name = ' '.join(temp_offer_name.split()) 77 brand = offer_name.split(' ')[0] 78 price = int(phone.find('span', {'class': 'price'}).get_text().replace('ден.', '') 79 .replace('ден', '') 80 .replace('.', '').strip()) 81 22 # Call to read the configuration file and connect to database 23 cinfo = config_read.get_databaseconfig("../postgresdb.config") 24 db_connection = psycopg2.connect( 25 database=cinfo[0], 26 host=cinfo[1], 27 user=cinfo[2], 28 password=cinfo[3] 29 ) 30 cur = db_connection.cursor() 31 32 try: 33 # Ledikom phone offers that are already in database 34 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/ledikom').text)) 35 36 database_offers = [] 37 38 for offer in offers: 39 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 40 offer['ram_memory'], 41 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 42 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 43 offer['image_url'], 44 offer['offer_url'], offer['last_updated'], offer['is_validated'], 45 offer['offer_description'], 46 offer['offer_shop_code']) 47 database_offers.append(phoneOffer) 48 49 new_offers = [] 50 51 ledikom_phone_urls = [ 52 'https://ledikom.mk/c/416/uredi/apple/iphone?limit=96', 53 'https://ledikom.mk/c/421/uredi/samsung/telefoni?limit=96', 54 'https://ledikom.mk/c/424/mobilni-telefoni/xiaomi/telefoni?limit=96', 55 'https://ledikom.mk/c/430/uredi/huawei/telefoni?limit=96', 56 'https://ledikom.mk/c/441/uredi/oneplus/telefoni?limit=96', 57 'https://ledikom.mk/c/413/uredi/google/telefoni?limit=96', 58 'https://ledikom.mk/c/411/uredi/honor/telefoni?limit=96', 59 'https://ledikom.mk/c/460/uredi/nokia/telefoni?limit=96', 60 'https://ledikom.mk/c/461/uredi/asus/telefoni?limit=96', 61 'https://ledikom.mk/c/488/proizvodi/oppo/telefoni?limit=96' 62 ] 63 64 for ledikom_url in ledikom_phone_urls: 65 66 # selenium is used because of the dynamic content of the page 82 67 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 83 driver1.get(offer_url) 84 # getting offer page html 85 offer_html = driver1.page_source 68 driver1.get(ledikom_url) 69 ledikom_html = driver1.page_source 70 71 # closing the driver so the safari instance can pair with another webdriver session 86 72 driver1.close() 87 73 88 soup2 = BeautifulSoup(offer_html, 'html.parser') 89 90 specifications = soup2.find('div', {'id': 'content'}).find('section', {'class': 'padding-section'}) \ 91 .find_all('div', {'class': 'container'})[1].find('div', {'class': 'col-md-7'}) \ 92 .find_all('div', {'class': 'row'}) 93 94 color = None 95 rom_memory = None 96 ram_memory = None 97 back_camera = None 98 operating_system = None 99 chipset = None 100 battery = None 101 cpu = None 102 front_camera = None 103 offer_shop_code = None 104 offer_description = None 105 106 if len(specifications) != 0: 107 colors_tags = specifications[0].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 108 temp_colors = [] 109 for color_tag in colors_tags: 110 temp_colors.append(color_tag.get_text().strip()) 111 color = ','.join(temp_colors) 112 113 if len(specifications) >= 2: 114 temp_rom = specifications[1].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 115 rom_list = [] 116 for rom in temp_rom: 117 rom_list.append(rom.get('title')) 118 rom_memory = ','.join(rom_list) 119 120 if len(specifications) >= 3: 121 temp_ram = specifications[2].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 122 ram_list = [] 123 for ram in temp_ram: 124 ram_list.append(ram.get('title')) 125 126 ram_memory = ','.join(ram_list) 127 128 if 'Xiaomi' in brand: 129 temp = color 130 color = rom_memory 131 rom_memory = temp 132 133 temp = ram_memory 134 ram_memory = color 135 color = temp 136 137 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 138 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 139 image_url, 140 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 141 142 for new_offer in new_offers: 143 flag = False 144 flag_price = False 145 offer_id = None 74 soup1 = BeautifulSoup(ledikom_html, 'html.parser') 75 76 phones = soup1.find('div', {'id': 'content'}) \ 77 .find('div', {'class': 'container'}).find('div', {'class': 'row'}).find('div', {'class': 'item-display'}) \ 78 .find_all('div', {'class': 'item-in-grid'}) 79 80 if len(phones) == 0: 81 continue 82 83 for phone in phones: 84 offer_url = 'https://ledikom.mk' + phone.find('a').get('href') 85 image_url = phone.find('a').find('img').get('src') 86 temp_offer_name = phone.find('div', {'class': 'item-name'}).find('a').get_text().strip() 87 offer_name = ' '.join(temp_offer_name.split()) 88 brand = offer_name.split(' ')[0] 89 price = int(phone.find('span', {'class': 'price'}).get_text().replace('ден.', '') 90 .replace('ден', '') 91 .replace('.', '').strip()) 92 93 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 94 driver1.get(offer_url) 95 # getting offer page html 96 offer_html = driver1.page_source 97 driver1.close() 98 99 soup2 = BeautifulSoup(offer_html, 'html.parser') 100 101 specifications = soup2.find('div', {'id': 'content'}).find('section', {'class': 'padding-section'}) \ 102 .find_all('div', {'class': 'container'})[1].find('div', {'class': 'col-md-7'}) \ 103 .find_all('div', {'class': 'row'}) 104 105 color = None 106 rom_memory = None 107 ram_memory = None 108 back_camera = None 109 operating_system = None 110 chipset = None 111 battery = None 112 cpu = None 113 front_camera = None 114 offer_shop_code = None 115 offer_description = None 116 117 if len(specifications) != 0: 118 colors_tags = specifications[0].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 119 temp_colors = [] 120 for color_tag in colors_tags: 121 temp_colors.append(color_tag.get_text().strip()) 122 color = ','.join(temp_colors) 123 124 if len(specifications) >= 2: 125 temp_rom = specifications[1].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 126 rom_list = [] 127 for rom in temp_rom: 128 rom_list.append(rom.get('title')) 129 rom_memory = ','.join(rom_list) 130 131 if len(specifications) >= 3: 132 temp_ram = specifications[2].find('div', {'class': 'col-md-12 col-xs-12'}).find_all('a') 133 ram_list = [] 134 for ram in temp_ram: 135 ram_list.append(ram.get('title')) 136 137 ram_memory = ','.join(ram_list) 138 139 if 'Xiaomi' in brand: 140 temp = color 141 color = rom_memory 142 rom_memory = temp 143 144 temp = ram_memory 145 ram_memory = color 146 color = temp 147 148 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 149 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 150 image_url, 151 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 152 153 for new_offer in new_offers: 154 flag = False 155 flag_price = False 156 offer_id = None 157 158 for old_offer in database_offers: 159 160 if new_offer.offer_name == old_offer.offer_name: 161 flag = True 162 if new_offer.price != old_offer.price: 163 flag_price = True 164 offer_id = old_offer.offer_id 165 166 if flag: 167 # print('ALREADY IN DATABASE') 168 # print(new_offer) 169 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 170 if flag_price: 171 print('PRICE CHANGED!') # CHANGE PRICE 172 print('offer id: ' + str(offer_id)) 173 headers = {'Content-type': 'application/json'} 174 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 175 headers=headers) 176 else: 177 print('ADDED') # ADD OFFER 178 print(new_offer) 179 headers = {'Content-type': 'application/json'} 180 requests.post('http://localhost:8080/phoneoffer/addoffer', 181 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 182 183 print('------------------------------------') 146 184 147 185 for old_offer in database_offers: 148 149 if new_offer.offer_name == old_offer.offer_name: 150 flag = True 151 if new_offer.price != old_offer.price: 152 flag_price = True 153 offer_id = old_offer.offer_id 154 155 if flag: 156 # print('ALREADY IN DATABASE') 157 # print(new_offer) 158 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 159 if flag_price: 160 print('PRICE CHANGED!') # CHANGE PRICE 161 print('offer id: ' + str(offer_id)) 162 headers = {'Content-type': 'application/json'} 163 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 164 headers=headers) 165 else: 166 print('ADDED') # ADD OFFER 167 print(new_offer) 168 headers = {'Content-type': 'application/json'} 169 requests.post('http://localhost:8080/phoneoffer/addoffer', 170 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 171 172 print('------------------------------------') 173 174 for old_offer in database_offers: 175 flag = False 176 for new_offer in new_offers: 177 if old_offer.offer_name == new_offer.offer_name: 178 flag = True 179 180 if not flag: 181 print('OFFER DELETED') 182 print(old_offer) 183 # DELETE OFFER 184 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 186 flag = False 187 for new_offer in new_offers: 188 if old_offer.offer_name == new_offer.offer_name: 189 flag = True 190 191 if not flag: 192 print('OFFER DELETED') 193 print(old_offer) 194 # DELETE OFFER 195 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 196 except Exception: 197 traceback.print_exc() 198 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 199 ' VALUES (%s, %s, %s);' 200 insert_value = (offer_shop, last_updated, 'failed') 201 cur.execute(insert_script, insert_value) 202 db_connection.commit() 203 cur.close() 204 db_connection.close() 205 else: 206 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 207 ' VALUES (%s, %s, %s);' 208 insert_value = (offer_shop, last_updated, 'success') 209 cur.execute(insert_script, insert_value) 210 db_connection.commit() 211 cur.close() 212 db_connection.close() 213 -
phonelux_scrappers/scrappers/mobelix_scrapper.py
rffd50db r47f4eaf 3 3 import unicodedata 4 4 from datetime import datetime 5 5 import traceback 6 6 import psycopg2 7 7 import config_read … … 19 19 is_validated = False 20 20 21 # Mobelix phone offers that are already in database 22 23 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobelix').text)) 24 25 database_offers = [] 26 27 for offer in offers: 28 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 29 offer['ram_memory'], 30 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 31 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 32 offer['image_url'], 33 offer['offer_url'], offer['last_updated'], offer['is_validated'], 34 offer['offer_description'], 35 offer['offer_shop_code']) 36 database_offers.append(phoneOffer) 37 38 new_offers = [] 39 40 for i in range(1, 17): 41 mobelix_url = "https://mobelix.com.mk/mk/mobilni-telefoni?page=" + str(i) 42 43 response1 = requests.get(mobelix_url) 44 soup1 = BeautifulSoup(response1.content, 'html.parser') 45 46 phones = soup1.find_all('div', {'class': 'p-2 rounded text-dark bg-white d-flex w-100'}) 47 48 for phone in phones: 49 offer_url = phone.find('a').get('href') 50 image_url = phone.find_all('div', {'class': 'col-12'})[0].find('img').get('src') 51 brand = phone.find_all('div', {'class': 'col-12'})[1].find('h5', {'class': 'mb-0'}).get_text().strip() 52 offer_name = phone.find_all('div', {'class': 'col-12'})[1] \ 53 .find('h3', {'class': 'h5 font-weight-normal'}).get_text().strip() 54 55 if 'Watch' in offer_name or 'Pad' in offer_name or 'Tab' in offer_name or 'Pods' in offer_name or 'Buds' in offer_name or 'HomePod' in offer_name: 56 continue 57 58 if brand not in offer_name: 59 offer_name = brand + " " + offer_name 60 61 temp_prices = phone.find_all('div', {'class': 'col-12'})[1] \ 62 .find('p', {'class': 'h5 price'}).get_text(separator='/').strip() 63 64 if len(temp_prices.split('/')) > 1: 65 price = int(float(temp_prices.split('/')[1].replace(',', '').replace('ден', '').strip())) 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 30 31 try: 32 # Mobelix phone offers that are already in database 33 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobelix').text)) 34 35 database_offers = [] 36 37 for offer in offers: 38 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 39 offer['ram_memory'], 40 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 41 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 42 offer['image_url'], 43 offer['offer_url'], offer['last_updated'], offer['is_validated'], 44 offer['offer_description'], 45 offer['offer_shop_code']) 46 database_offers.append(phoneOffer) 47 48 new_offers = [] 49 50 for i in range(1, 17): 51 mobelix_url = "https://mobelix.com.mk/mk/mobilni-telefoni?page=" + str(i) 52 53 response1 = requests.get(mobelix_url) 54 soup1 = BeautifulSoup(response1.content, 'html.parser') 55 56 phones = soup1.find_all('div', {'class': 'p-2 rounded text-dark bg-white d-flex w-100'}) 57 58 for phone in phones: 59 offer_url = phone.find('a').get('href') 60 image_url = phone.find_all('div', {'class': 'col-12'})[0].find('img').get('src') 61 brand = phone.find_all('div', {'class': 'col-12'})[1].find('h5', {'class': 'mb-0'}).get_text().strip() 62 offer_name = phone.find_all('div', {'class': 'col-12'})[1] \ 63 .find('h3', {'class': 'h5 font-weight-normal'}).get_text().strip() 64 65 if 'Watch' in offer_name or 'Pad' in offer_name or 'Tab' in offer_name or 'Pods' in offer_name or 'Buds' in offer_name or 'HomePod' in offer_name: 66 continue 67 68 if brand not in offer_name: 69 offer_name = brand + " " + offer_name 70 71 temp_prices = phone.find_all('div', {'class': 'col-12'})[1] \ 72 .find('p', {'class': 'h5 price'}).get_text(separator='/').strip() 73 74 if len(temp_prices.split('/')) > 1: 75 price = int(float(temp_prices.split('/')[1].replace(',', '').replace('ден', '').strip())) 76 else: 77 price = int(float(temp_prices.split('/')[0].replace(',', '').replace('ден', '').strip())) 78 79 response2 = requests.get(offer_url) 80 soup2 = BeautifulSoup(response2.content, 'html.parser') 81 82 colors_divs = soup2.find('div', {'class': 'color-wrapper mt-2 mb-1'}) \ 83 .find_all('div', {'class': 'color-box d-inline-block'}) # color div tags 84 85 temp_colors = [] 86 for div in colors_divs: 87 temp_colors.append(div.get('title')) 88 89 color = ",".join(temp_colors) # available colors for offer 90 91 tables = soup2.find('div', {'class': 'mobelix-specs table-white bordered-table'}).find_all('table') 92 93 operating_system = None 94 chipset = None 95 battery = None 96 ram_memory = None 97 rom_memory = None 98 front_camera = '' 99 back_camera = '' 100 cpu = None 101 offer_shop_code = None 102 offer_description = None 103 104 for table in tables: 105 for cell in table.find_all('td'): 106 if cell.get('data-spec') is None: 107 continue 108 109 if cell.get('data-spec') == 'os': 110 operating_system = unicodedata.normalize('NFKD', cell.get_text().strip()) 111 112 if cell.get('data-spec') == 'chipset': 113 chipset = unicodedata.normalize('NFKD', cell.get_text().strip()) 114 115 if cell.get('data-spec') == 'cpu': 116 cpu = unicodedata.normalize('NFKD', cell.get_text().strip()) 117 118 if cell.get('data-spec') == 'internalmemory': 119 temp_rom = [] 120 temp_ram = [] 121 temp_internalmemory = unicodedata.normalize('NFKD', cell.get_text().strip()) 122 for internalmemory in temp_internalmemory.split(','): 123 temp_rom.append(internalmemory.strip().split(' ')[0]) 124 if len(internalmemory.strip().split(' ')) > 1: 125 temp_ram.append(internalmemory.strip().split(' ')[1]) 126 rom_memory = ','.join(temp_rom) 127 ram_memory = ','.join(temp_ram) 128 129 if cell.get('data-spec') == 'cam1modules' or cell.get('data-spec') == 'cam1features' or cell.get( 130 'data-spec') == 'cam1video': 131 back_camera += unicodedata.normalize('NFKD', cell.get_text().strip()) + '\n' 132 133 if cell.get('data-spec') == 'cam2modules' or cell.get('data-spec') == 'cam2features' or cell.get( 134 'data-spec') == 'cam2video': 135 front_camera += unicodedata.normalize('NFKD', cell.get_text().strip()) + '\n' 136 137 if cell.get('data-spec') == 'batdescription1': 138 battery = unicodedata.normalize('NFKD', cell.get_text().strip()) 139 140 if front_camera == 'No': 141 front_camera = None 142 143 if back_camera == 'No': 144 back_camera = None 145 146 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 147 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 148 image_url, 149 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 150 151 152 for new_offer in new_offers: 153 flag = False 154 flag_price = False 155 offer_id = None 156 157 for old_offer in database_offers: 158 159 if new_offer.offer_name == old_offer.offer_name: 160 flag = True 161 if new_offer.price != old_offer.price: 162 flag_price = True 163 offer_id = old_offer.offer_id 164 165 if flag: 166 # print('ALREADY IN DATABASE') 167 # print(new_offer) 168 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 169 if flag_price: 170 print('PRICE CHANGED!') # CHANGE PRICE 171 print('offer id: ' + str(offer_id)) 172 headers = {'Content-type': 'application/json'} 173 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 174 headers=headers) 66 175 else: 67 price = int(float(temp_prices.split('/')[0].replace(',', '').replace('ден', '').strip())) 68 69 response2 = requests.get(offer_url) 70 soup2 = BeautifulSoup(response2.content, 'html.parser') 71 72 colors_divs = soup2.find('div', {'class': 'color-wrapper mt-2 mb-1'}) \ 73 .find_all('div', {'class': 'color-box d-inline-block'}) # color div tags 74 75 temp_colors = [] 76 for div in colors_divs: 77 temp_colors.append(div.get('title')) 78 79 color = ",".join(temp_colors) # available colors for offer 80 81 tables = soup2.find('div', {'class': 'mobelix-specs table-white bordered-table'}).find_all('table') 82 83 operating_system = None 84 chipset = None 85 battery = None 86 ram_memory = None 87 rom_memory = None 88 front_camera = '' 89 back_camera = '' 90 cpu = None 91 offer_shop_code = None 92 offer_description = None 93 94 for table in tables: 95 for cell in table.find_all('td'): 96 if cell.get('data-spec') is None: 97 continue 98 99 if cell.get('data-spec') == 'os': 100 operating_system = unicodedata.normalize('NFKD', cell.get_text().strip()) 101 102 if cell.get('data-spec') == 'chipset': 103 chipset = unicodedata.normalize('NFKD', cell.get_text().strip()) 104 105 if cell.get('data-spec') == 'cpu': 106 cpu = unicodedata.normalize('NFKD', cell.get_text().strip()) 107 108 if cell.get('data-spec') == 'internalmemory': 109 temp_rom = [] 110 temp_ram = [] 111 temp_internalmemory = unicodedata.normalize('NFKD', cell.get_text().strip()) 112 for internalmemory in temp_internalmemory.split(','): 113 temp_rom.append(internalmemory.strip().split(' ')[0]) 114 if len(internalmemory.strip().split(' ')) > 1: 115 temp_ram.append(internalmemory.strip().split(' ')[1]) 116 rom_memory = ','.join(temp_rom) 117 ram_memory = ','.join(temp_ram) 118 119 if cell.get('data-spec') == 'cam1modules' or cell.get('data-spec') == 'cam1features' or cell.get( 120 'data-spec') == 'cam1video': 121 back_camera += unicodedata.normalize('NFKD', cell.get_text().strip()) + '\n' 122 123 if cell.get('data-spec') == 'cam2modules' or cell.get('data-spec') == 'cam2features' or cell.get( 124 'data-spec') == 'cam2video': 125 front_camera += unicodedata.normalize('NFKD', cell.get_text().strip()) + '\n' 126 127 if cell.get('data-spec') == 'batdescription1': 128 battery = unicodedata.normalize('NFKD', cell.get_text().strip()) 129 130 if front_camera == 'No': 131 front_camera = None 132 133 if back_camera == 'No': 134 back_camera = None 135 136 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 137 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 138 image_url, 139 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 140 141 142 for new_offer in new_offers: 143 flag = False 144 flag_price = False 145 offer_id = None 176 print('ADDED') # ADD OFFER 177 print(new_offer) 178 headers = {'Content-type': 'application/json'} 179 requests.post('http://localhost:8080/phoneoffer/addoffer', 180 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 181 182 print('------------------------------------') 146 183 147 184 for old_offer in database_offers: 148 149 if new_offer.offer_name == old_offer.offer_name: 150 flag = True 151 if new_offer.price != old_offer.price: 152 flag_price = True 153 offer_id = old_offer.offer_id 154 155 if flag: 156 # print('ALREADY IN DATABASE') 157 # print(new_offer) 158 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 159 if flag_price: 160 print('PRICE CHANGED!') # CHANGE PRICE 161 print('offer id: ' + str(offer_id)) 162 headers = {'Content-type': 'application/json'} 163 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 164 headers=headers) 165 else: 166 print('ADDED') # ADD OFFER 167 print(new_offer) 168 headers = {'Content-type': 'application/json'} 169 requests.post('http://localhost:8080/phoneoffer/addoffer', 170 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 171 172 print('------------------------------------') 173 174 for old_offer in database_offers: 175 flag = False 176 for new_offer in new_offers: 177 if old_offer.offer_name == new_offer.offer_name: 178 flag = True 179 180 if not flag: 181 print('OFFER DELETED') 182 print(old_offer) 183 # DELETE OFFER 184 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 185 flag = False 186 for new_offer in new_offers: 187 if old_offer.offer_name == new_offer.offer_name: 188 flag = True 189 190 if not flag: 191 print('OFFER DELETED') 192 print(old_offer) 193 # DELETE OFFER 194 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 195 except Exception: 196 traceback.print_exc() 197 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 198 ' VALUES (%s, %s, %s);' 199 insert_value = (offer_shop, last_updated, 'failed') 200 cur.execute(insert_script, insert_value) 201 db_connection.commit() 202 cur.close() 203 db_connection.close() 204 else: 205 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 206 ' VALUES (%s, %s, %s);' 207 insert_value = (offer_shop, last_updated, 'success') 208 cur.execute(insert_script, insert_value) 209 db_connection.commit() 210 cur.close() 211 db_connection.close() 212 -
phonelux_scrappers/scrappers/mobigo_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 18 19 is_validated = False 19 20 20 # Mobi Go phone offers that are already in database 21 22 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobigo').text)) 23 24 database_offers = [] 25 26 for offer in offers: 27 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 28 offer['ram_memory'], 29 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 30 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 31 offer['image_url'], 32 offer['offer_url'], offer['last_updated'], offer['is_validated'], 33 offer['offer_description'], 34 offer['offer_shop_code']) 35 database_offers.append(phoneOffer) 36 37 new_offers = [] 38 39 40 for i in range(1, 6): 41 mobigo_url = "https://mobigo.mk/page/" + str(i) + "/" 42 43 response1 = requests.get(mobigo_url) 44 45 soup1 = BeautifulSoup(response1.content, 'html.parser') 46 47 phone_sections = soup1.find_all('ul', {'class': 'recent-posts'}) 48 phones = phone_sections[len(phone_sections) - 1].find_all('li') 49 50 for phone in phones: 51 offer_url = phone.find('div', {'class', 'post-thumb'}).find('a').get('href') # offer url 52 image_url = phone.find('div', {'class', 'post-thumb'}).find('a').find('img').get('src') # image url 53 offer_name = phone.find('div', {'class', 'post-content'}).find_all('h2')[0].get_text().strip() # offer_name 54 55 if "Watch" in offer_name or "Tab" in offer_name: # if the product is watch or tablet, continue 56 continue 57 58 price = int(float(phone.find('div', {'class', 'post-content'}).find_all('h2')[1] \ 59 .get_text().replace('ден.', '').replace('.', '').strip())) # price 60 61 response2 = requests.get(offer_url) 62 soup2 = BeautifulSoup(response2.content, 'html.parser') 63 64 brand = soup2.find('a', {'rel': 'category tag'}).get_text().strip() # brand 65 66 if brand not in offer_name: 67 offer_name = brand + " " + offer_name 68 69 specifications = soup2.find('table', {'id': 'singlet'}).find_all('tr') 70 71 ram_memory = None 72 rom_memory = None 73 battery = None 74 back_camera = None 75 front_camera = None 76 chipset = None 77 operating_system = None 78 cpu = None 79 offer_shop_code = None 80 offer_description = None 81 color = None 82 83 for specification in specifications: 84 if specification.find('td') == None: 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 30 31 try: 32 # Mobi Go phone offers that are already in database 33 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobigo').text)) 34 35 database_offers = [] 36 37 for offer in offers: 38 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 39 offer['ram_memory'], 40 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 41 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 42 offer['image_url'], 43 offer['offer_url'], offer['last_updated'], offer['is_validated'], 44 offer['offer_description'], 45 offer['offer_shop_code']) 46 database_offers.append(phoneOffer) 47 48 new_offers = [] 49 50 51 for i in range(1, 6): 52 mobigo_url = "https://mobigo.mk/page/" + str(i) + "/" 53 54 response1 = requests.get(mobigo_url) 55 56 soup1 = BeautifulSoup(response1.content, 'html.parser') 57 58 phone_sections = soup1.find_all('ul', {'class': 'recent-posts'}) 59 phones = phone_sections[len(phone_sections) - 1].find_all('li') 60 61 for phone in phones: 62 offer_url = phone.find('div', {'class', 'post-thumb'}).find('a').get('href') # offer url 63 image_url = phone.find('div', {'class', 'post-thumb'}).find('a').find('img').get('src') # image url 64 offer_name = phone.find('div', {'class', 'post-content'}).find_all('h2')[0].get_text().strip() # offer_name 65 66 if "Watch" in offer_name or "Tab" in offer_name: # if the product is watch or tablet, continue 85 67 continue 86 68 87 # operating system 88 if specification.find('td').get_text() == "Платформа": 89 if specification.find('i').get_text() != "/": 90 operating_system = specification.find('i').get_text().strip() 91 else: 92 operating_system = None 93 94 # chipset 95 if specification.find('td').get_text() == "Chipset": 96 if specification.find('i').get_text() != "/": 97 chipset = specification.find('i').get_text().strip() 98 else: 99 chipset = None 100 101 # ram and rom memory 102 if specification.find('td').get_text() == "Меморија": 103 if specification.find('i').get_text() != "/": 104 rom_memory = specification.find('i').get_text().replace(',', '').split(' ')[0].strip() 105 ram_memory = specification.find('i').get_text().replace(',', '').split(' ')[1].strip() 106 else: 107 rom_memory = None 108 ram_memory = None 109 110 # back camera 111 if specification.find('td').get_text() == "Главна Камера": 112 if specification.find('i').get_text() != "/": 113 back_camera = specification.find('i').get_text().strip() 114 else: 115 back_camera = None 116 117 # front camera 118 if specification.find('td').get_text() == "Селфи Камера": 119 if specification.find('i').get_text() != "/": 120 front_camera = specification.find('i').get_text().strip() 121 else: 122 front_camera = None 123 124 # battery 125 if specification.find('td').get_text() == "Батерија": 126 if specification.find('i').get_text() != "/": 127 battery = specification.find('i').get_text().strip() 128 else: 129 battery = None 130 131 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 132 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 133 image_url, 134 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 135 136 137 for new_offer in new_offers: 138 flag = False 139 flag_price = False 140 offer_id = None 69 price = int(float(phone.find('div', {'class', 'post-content'}).find_all('h2')[1] \ 70 .get_text().replace('ден.', '').replace('.', '').strip())) # price 71 72 response2 = requests.get(offer_url) 73 soup2 = BeautifulSoup(response2.content, 'html.parser') 74 75 brand = soup2.find('a', {'rel': 'category tag'}).get_text().strip() # brand 76 77 if brand not in offer_name: 78 offer_name = brand + " " + offer_name 79 80 specifications = soup2.find('table', {'id': 'singlet'}).find_all('tr') 81 82 ram_memory = None 83 rom_memory = None 84 battery = None 85 back_camera = None 86 front_camera = None 87 chipset = None 88 operating_system = None 89 cpu = None 90 offer_shop_code = None 91 offer_description = None 92 color = None 93 94 for specification in specifications: 95 if specification.find('td') == None: 96 continue 97 98 # operating system 99 if specification.find('td').get_text() == "Платформа": 100 if specification.find('i').get_text() != "/": 101 operating_system = specification.find('i').get_text().strip() 102 else: 103 operating_system = None 104 105 # chipset 106 if specification.find('td').get_text() == "Chipset": 107 if specification.find('i').get_text() != "/": 108 chipset = specification.find('i').get_text().strip() 109 else: 110 chipset = None 111 112 # ram and rom memory 113 if specification.find('td').get_text() == "Меморија": 114 if specification.find('i').get_text() != "/": 115 rom_memory = specification.find('i').get_text().replace(',', '').split(' ')[0].strip() 116 ram_memory = specification.find('i').get_text().replace(',', '').split(' ')[1].strip() 117 else: 118 rom_memory = None 119 ram_memory = None 120 121 # back camera 122 if specification.find('td').get_text() == "Главна Камера": 123 if specification.find('i').get_text() != "/": 124 back_camera = specification.find('i').get_text().strip() 125 else: 126 back_camera = None 127 128 # front camera 129 if specification.find('td').get_text() == "Селфи Камера": 130 if specification.find('i').get_text() != "/": 131 front_camera = specification.find('i').get_text().strip() 132 else: 133 front_camera = None 134 135 # battery 136 if specification.find('td').get_text() == "Батерија": 137 if specification.find('i').get_text() != "/": 138 battery = specification.find('i').get_text().strip() 139 else: 140 battery = None 141 142 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 143 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 144 image_url, 145 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 146 147 148 for new_offer in new_offers: 149 flag = False 150 flag_price = False 151 offer_id = None 152 153 for old_offer in database_offers: 154 155 if new_offer.offer_name == old_offer.offer_name: 156 flag = True 157 if new_offer.price != old_offer.price: 158 flag_price = True 159 offer_id = old_offer.offer_id 160 161 if flag: 162 print('ALREADY IN DATABASE') 163 print(new_offer) 164 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 165 if flag_price: 166 print('PRICE CHANGED!') # CHANGE PRICE 167 print('offer id: ' + str(offer_id)) 168 headers = {'Content-type': 'application/json'} 169 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 170 headers=headers) 171 else: 172 print('ADDED') # ADD OFFER 173 print(new_offer) 174 headers = {'Content-type': 'application/json'} 175 requests.post('http://localhost:8080/phoneoffer/addoffer', 176 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 177 178 print('------------------------------------') 141 179 142 180 for old_offer in database_offers: 143 144 if new_offer.offer_name == old_offer.offer_name: 145 flag = True 146 if new_offer.price != old_offer.price: 147 flag_price = True 148 offer_id = old_offer.offer_id 149 150 if flag: 151 print('ALREADY IN DATABASE') 152 print(new_offer) 153 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 154 if flag_price: 155 print('PRICE CHANGED!') # CHANGE PRICE 156 print('offer id: ' + str(offer_id)) 157 headers = {'Content-type': 'application/json'} 158 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 159 headers=headers) 160 else: 161 print('ADDED') # ADD OFFER 162 print(new_offer) 163 headers = {'Content-type': 'application/json'} 164 requests.post('http://localhost:8080/phoneoffer/addoffer', 165 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 166 167 print('------------------------------------') 168 169 for old_offer in database_offers: 170 flag = False 171 for new_offer in new_offers: 172 if old_offer.offer_name == new_offer.offer_name: 173 flag = True 174 175 if not flag: 176 print('OFFER DELETED') 177 print(old_offer) 178 # DELETE OFFER 179 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 181 flag = False 182 for new_offer in new_offers: 183 if old_offer.offer_name == new_offer.offer_name: 184 flag = True 185 186 if not flag: 187 print('OFFER DELETED') 188 print(old_offer) 189 # DELETE OFFER 190 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 191 except Exception: 192 traceback.print_exc() 193 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 194 ' VALUES (%s, %s, %s);' 195 insert_value = (offer_shop, last_updated, 'failed') 196 cur.execute(insert_script, insert_value) 197 db_connection.commit() 198 cur.close() 199 db_connection.close() 200 else: 201 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 202 ' VALUES (%s, %s, %s);' 203 insert_value = (offer_shop, last_updated, 'success') 204 cur.execute(insert_script, insert_value) 205 db_connection.commit() 206 cur.close() 207 db_connection.close() -
phonelux_scrappers/scrappers/mobilezone_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 18 19 is_validated = False 19 20 20 # Mobile Zone phone offers that are already in database 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 21 30 22 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobilezone').text)) 31 try: 32 # Mobile Zone phone offers that are already in database 33 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobilezone').text)) 23 34 24 database_offers = []35 database_offers = [] 25 36 26 for offer in offers:27 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],28 offer['ram_memory'],29 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],30 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],31 offer['image_url'],32 offer['offer_url'], offer['last_updated'], offer['is_validated'],33 offer['offer_description'],34 offer['offer_shop_code'])35 database_offers.append(phoneOffer)37 for offer in offers: 38 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 39 offer['ram_memory'], 40 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 41 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 42 offer['image_url'], 43 offer['offer_url'], offer['last_updated'], offer['is_validated'], 44 offer['offer_description'], 45 offer['offer_shop_code']) 46 database_offers.append(phoneOffer) 36 47 37 new_offers = []48 new_offers = [] 38 49 39 for i in range(1, 3):40 mobilezone_url = 'https://mobilezone.mk/produkt-kategorija/telefoni/novi-telefoni/page/' + str(i) + '/'50 for i in range(1, 3): 51 mobilezone_url = 'https://mobilezone.mk/produkt-kategorija/telefoni/novi-telefoni/page/' + str(i) + '/' 41 52 42 response1 = requests.get(mobilezone_url)43 soup1 = BeautifulSoup(response1.content, 'html.parser')53 response1 = requests.get(mobilezone_url) 54 soup1 = BeautifulSoup(response1.content, 'html.parser') 44 55 45 phones = soup1.find('ul', {46 'class': 'products columns-tablet-2 columns-mobile-2 --skin-proto rey-wcGap-default rey-wcGrid-default '47 '--paginated columns-4'}).find_all('li')56 phones = soup1.find('ul', { 57 'class': 'products columns-tablet-2 columns-mobile-2 --skin-proto rey-wcGap-default rey-wcGrid-default ' 58 '--paginated columns-4'}).find_all('li') 48 59 49 for phone in phones:50 offer_url = phone.find('a', {'class': 'woocommerce-LoopProduct-link woocommerce-loop-product__link'}).get(51 'href')52 image_url = phone.find('a', {'class': 'woocommerce-LoopProduct-link woocommerce-loop-product__link'}) \53 .find('img').get('data-lazy-src')60 for phone in phones: 61 offer_url = phone.find('a', {'class': 'woocommerce-LoopProduct-link woocommerce-loop-product__link'}).get( 62 'href') 63 image_url = phone.find('a', {'class': 'woocommerce-LoopProduct-link woocommerce-loop-product__link'}) \ 64 .find('img').get('data-lazy-src') 54 65 55 brand_section = phone.find('div', {'class': 'rey-productInner'}).find('div', {'class': 'rey-brandLink'})66 brand_section = phone.find('div', {'class': 'rey-productInner'}).find('div', {'class': 'rey-brandLink'}) 56 67 57 if brand_section is not None: 58 brand = brand_section.find('a').get_text().strip() 68 if brand_section is not None: 69 brand = brand_section.find('a').get_text().strip() 70 else: 71 brand = None 72 73 offer_name = phone.find('h2', {'class': 'woocommerce-loop-product__title'}).find('a').get_text().strip() 74 75 if brand is not None and brand not in offer_name: 76 offer_name = brand + ' ' + offer_name 77 78 price_tag = phone.find('span', {'class': 'woocommerce-Price-amount amount'}) 79 price = None 80 81 if price_tag is not None: 82 price = int(unicodedata.normalize('NFKD', price_tag.find('bdi').get_text() 83 .replace(',', '') 84 .replace('ден', '').strip())) 85 else: 86 continue 87 88 response2 = requests.get(offer_url) 89 soup2 = BeautifulSoup(response2.text, 'html.parser') 90 91 specifications = soup2.find('table', {'class': 'woocommerce-product-attributes shop_attributes'}).find_all('tr') 92 93 back_camera = None 94 front_camera = None 95 rom_memory = None 96 ram_memory = None 97 operating_system = None 98 cpu = None 99 chipset = None 100 offer_description = None 101 offer_shop_code = None 102 battery = None 103 color = None 104 105 for specification in specifications: 106 if 'Главна камера' in specification.find('th').get_text(): 107 back_camera = specification.find('td').get_text().strip() 108 109 if 'Селфи камера' in specification.find('th').get_text(): 110 front_camera = specification.find('td').get_text().strip() 111 112 if 'Батерија' in specification.find('th').get_text(): 113 battery = specification.find('td').get_text().strip() 114 115 if 'Меморија' in specification.find('th').get_text(): 116 rom_memory = specification.find('td').get_text().strip() 117 118 if 'Боја' in specification.find('th').get_text(): 119 color = specification.find('td').get_text().strip() 120 121 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 122 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 123 image_url, 124 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 125 126 for new_offer in new_offers: 127 flag = False 128 flag_price = False 129 offer_id = None 130 131 for old_offer in database_offers: 132 133 if new_offer.offer_name == old_offer.offer_name: 134 flag = True 135 if new_offer.price != old_offer.price: 136 flag_price = True 137 offer_id = old_offer.offer_id 138 139 if flag: 140 # print('ALREADY IN DATABASE') 141 # print(new_offer) 142 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 143 if flag_price: 144 print('PRICE CHANGED!') # CHANGE PRICE 145 print('offer id: ' + str(offer_id)) 146 headers = {'Content-type': 'application/json'} 147 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 148 headers=headers) 59 149 else: 60 brand = None 150 print('ADDED') # ADD OFFER 151 print(new_offer) 152 headers = {'Content-type': 'application/json'} 153 requests.post('http://localhost:8080/phoneoffer/addoffer', 154 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 61 155 62 offer_name = phone.find('h2', {'class': 'woocommerce-loop-product__title'}).find('a').get_text().strip() 63 64 if brand is not None and brand not in offer_name: 65 offer_name = brand + ' ' + offer_name 66 67 price_tag = phone.find('span', {'class': 'woocommerce-Price-amount amount'}) 68 price = None 69 70 if price_tag is not None: 71 price = int(unicodedata.normalize('NFKD', price_tag.find('bdi').get_text() 72 .replace(',', '') 73 .replace('ден', '').strip())) 74 else: 75 continue 76 77 response2 = requests.get(offer_url) 78 soup2 = BeautifulSoup(response2.text, 'html.parser') 79 80 specifications = soup2.find('table', {'class': 'woocommerce-product-attributes shop_attributes'}).find_all('tr') 81 82 back_camera = None 83 front_camera = None 84 rom_memory = None 85 ram_memory = None 86 operating_system = None 87 cpu = None 88 chipset = None 89 offer_description = None 90 offer_shop_code = None 91 battery = None 92 color = None 93 94 for specification in specifications: 95 if 'Главна камера' in specification.find('th').get_text(): 96 back_camera = specification.find('td').get_text().strip() 97 98 if 'Селфи камера' in specification.find('th').get_text(): 99 front_camera = specification.find('td').get_text().strip() 100 101 if 'Батерија' in specification.find('th').get_text(): 102 battery = specification.find('td').get_text().strip() 103 104 if 'Меморија' in specification.find('th').get_text(): 105 rom_memory = specification.find('td').get_text().strip() 106 107 if 'Боја' in specification.find('th').get_text(): 108 color = specification.find('td').get_text().strip() 109 110 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 111 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 112 image_url, 113 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 114 115 for new_offer in new_offers: 116 flag = False 117 flag_price = False 118 offer_id = None 156 print('------------------------------------') 119 157 120 158 for old_offer in database_offers: 159 flag = False 160 for new_offer in new_offers: 161 if old_offer.offer_name == new_offer.offer_name: 162 flag = True 121 163 122 if new_offer.offer_name == old_offer.offer_name: 123 flag = True 124 if new_offer.price != old_offer.price: 125 flag_price = True 126 offer_id = old_offer.offer_id 127 128 if flag: 129 # print('ALREADY IN DATABASE') 130 # print(new_offer) 131 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 132 if flag_price: 133 print('PRICE CHANGED!') # CHANGE PRICE 134 print('offer id: ' + str(offer_id)) 135 headers = {'Content-type': 'application/json'} 136 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 137 headers=headers) 138 else: 139 print('ADDED') # ADD OFFER 140 print(new_offer) 141 headers = {'Content-type': 'application/json'} 142 requests.post('http://localhost:8080/phoneoffer/addoffer', 143 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 144 145 print('------------------------------------') 146 147 for old_offer in database_offers: 148 flag = False 149 for new_offer in new_offers: 150 if old_offer.offer_name == new_offer.offer_name: 151 flag = True 152 153 if not flag: 154 print('OFFER DELETED') 155 print(old_offer) 156 # DELETE OFFER 157 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 164 if not flag: 165 print('OFFER DELETED') 166 print(old_offer) 167 # DELETE OFFER 168 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 169 except Exception: 170 traceback.print_exc() 171 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 172 ' VALUES (%s, %s, %s);' 173 insert_value = (offer_shop, last_updated, 'failed') 174 cur.execute(insert_script, insert_value) 175 db_connection.commit() 176 cur.close() 177 db_connection.close() 178 else: 179 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 180 ' VALUES (%s, %s, %s);' 181 insert_value = (offer_shop, last_updated, 'success') 182 cur.execute(insert_script, insert_value) 183 db_connection.commit() 184 cur.close() 185 db_connection.close() -
phonelux_scrappers/scrappers/mobitech_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 14 15 sys.stdout = open(file_path, "w") 15 16 16 17 mobitech_url = "https://mobitech.mk/shop/"18 19 response1 = requests.get(mobitech_url)20 21 soup1 = BeautifulSoup(response1.content, 'html.parser')22 23 phones = soup1.find_all('div', {'class': 'jet-woo-products__inner-box'})24 25 17 offer_shop = "Mobitech" # offer shop 26 18 last_updated = datetime.now().date() 27 19 is_validated = False 28 20 29 # Mobitech phone offers that are already in database 21 # Call to read the configuration file and connect to database 22 cinfo = config_read.get_databaseconfig("../postgresdb.config") 23 db_connection = psycopg2.connect( 24 database=cinfo[0], 25 host=cinfo[1], 26 user=cinfo[2], 27 password=cinfo[3] 28 ) 29 cur = db_connection.cursor() 30 30 31 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobitech').text)) 31 try: 32 mobitech_url = "https://mobitech.mk/shop/" 32 33 33 database_offers = [] 34 response1 = requests.get(mobitech_url) 34 35 35 for offer in offers: 36 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 37 offer['ram_memory'], 38 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 39 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 40 offer['image_url'], 41 offer['offer_url'], offer['last_updated'], offer['is_validated'], 42 offer['offer_description'], 43 offer['offer_shop_code']) 44 database_offers.append(phoneOffer) 36 soup1 = BeautifulSoup(response1.content, 'html.parser') 45 37 46 new_offers = [] 38 phones = soup1.find_all('div', {'class': 'jet-woo-products__inner-box'}) 47 39 48 for phone in phones: 49 offer_url = phone.find('h5', {'class': 'jet-woo-product-title'}).find('a').get('href') # url 50 image_url = phone.find('div', {'class': 'jet-woo-product-thumbnail'}).find('img').get('src') # image 51 brand = phone.find_next('div', {'class': 'jet-woo-product-categories'}).find('a').get_text().strip() # brand 52 offer_name = phone.find('h5', {'class': 'jet-woo-product-title'}).find('a').get_text().strip() # offer_name 53 if brand not in offer_name: 54 offer_name = brand+" "+offer_name 55 temp_prices = phone.find('div', {'class': 'jet-woo-product-price'}).find_all('bdi') 56 price = int(float(temp_prices[len(temp_prices) - 1].get_text().replace("ден", "").replace(",", "").strip())) # price 40 # Mobitech phone offers that are already in database 41 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/mobitech').text)) 57 42 58 response2 = requests.get(offer_url) 59 soup2 = BeautifulSoup(response2.content, 'html.parser') 43 database_offers = [] 60 44 61 specifications = soup2.find_all('h2', {'class': 'elementor-heading-title elementor-size-default'}) 45 for offer in offers: 46 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 47 offer['ram_memory'], 48 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 49 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 50 offer['image_url'], 51 offer['offer_url'], offer['last_updated'], offer['is_validated'], 52 offer['offer_description'], 53 offer['offer_shop_code']) 54 database_offers.append(phoneOffer) 62 55 63 ram_memory = None 64 rom_memory = None 65 battery = None 66 back_camera = None 67 front_camera = None 68 operating_system = None 69 chipset = None 70 color = None 71 offer_shop_code = None 72 cpu = None 73 offer_description = None 56 new_offers = [] 74 57 75 for specification in specifications: 76 # rom memory 77 if specification.get_text().startswith("Меморија:"): 78 rom_memory = specification.get_text().split("Меморија:")[1].strip() 79 if rom_memory == "Нема" or rom_memory == "/": 80 rom_memory = None 58 for phone in phones: 59 offer_url = phone.find('h5', {'class': 'jet-woo-product-title'}).find('a').get('href') # url 60 image_url = phone.find('div', {'class': 'jet-woo-product-thumbnail'}).find('img').get('src') # image 61 brand = phone.find_next('div', {'class': 'jet-woo-product-categories'}).find('a').get_text().strip() # brand 62 offer_name = phone.find('h5', {'class': 'jet-woo-product-title'}).find('a').get_text().strip() # offer_name 63 if brand not in offer_name: 64 offer_name = brand+" "+offer_name 65 temp_prices = phone.find('div', {'class': 'jet-woo-product-price'}).find_all('bdi') 66 price = int(float(temp_prices[len(temp_prices) - 1].get_text().replace("ден", "").replace(",", "").strip())) # price 81 67 82 # ram memory 83 if specification.get_text().startswith("РАМ Меморија:"): 84 ram_memory = specification.get_text().split("РАМ Меморија:")[1].replace('RAM', '')\ 85 .replace('Ram', '').strip() 86 if ram_memory == "Нема" or ram_memory == "/": 87 ram_memory = None 68 response2 = requests.get(offer_url) 69 soup2 = BeautifulSoup(response2.content, 'html.parser') 88 70 89 # camera 90 if specification.get_text().startswith("Камера:"): 91 back_camera = specification.get_text().split("Камера:")[1].strip() 92 if back_camera == "Нема": 93 back_camera = None 71 specifications = soup2.find_all('h2', {'class': 'elementor-heading-title elementor-size-default'}) 94 72 95 # operating system 96 if specification.get_text().startswith("Оперативен систем:"): 97 operating_system = specification.get_text().split("Оперативен систем:")[1].split(",")[0].strip() 98 if operating_system == "Нема": 99 operating_system = None 73 ram_memory = None 74 rom_memory = None 75 battery = None 76 back_camera = None 77 front_camera = None 78 operating_system = None 79 chipset = None 80 color = None 81 offer_shop_code = None 82 cpu = None 83 offer_description = None 100 84 101 # battery 102 if specification.get_text().startswith("Батерија:"): 103 battery = specification.get_text().split("Батерија:")[1].strip() 104 if battery == "Нема": 105 battery = None 85 for specification in specifications: 86 # rom memory 87 if specification.get_text().startswith("Меморија:"): 88 rom_memory = specification.get_text().split("Меморија:")[1].strip() 89 if rom_memory == "Нема" or rom_memory == "/": 90 rom_memory = None 106 91 107 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 108 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 109 image_url, 110 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 92 # ram memory 93 if specification.get_text().startswith("РАМ Меморија:"): 94 ram_memory = specification.get_text().split("РАМ Меморија:")[1].replace('RAM', '')\ 95 .replace('Ram', '').strip() 96 if ram_memory == "Нема" or ram_memory == "/": 97 ram_memory = None 111 98 112 for new_offer in new_offers: 113 flag = False 114 flag_price = False 115 offer_id = None 99 # camera 100 if specification.get_text().startswith("Камера:"): 101 back_camera = specification.get_text().split("Камера:")[1].strip() 102 if back_camera == "Нема": 103 back_camera = None 104 105 # operating system 106 if specification.get_text().startswith("Оперативен систем:"): 107 operating_system = specification.get_text().split("Оперативен систем:")[1].split(",")[0].strip() 108 if operating_system == "Нема": 109 operating_system = None 110 111 # battery 112 if specification.get_text().startswith("Батерија:"): 113 battery = specification.get_text().split("Батерија:")[1].strip() 114 if battery == "Нема": 115 battery = None 116 117 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 118 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 119 image_url, 120 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 121 122 for new_offer in new_offers: 123 flag = False 124 flag_price = False 125 offer_id = None 126 127 for old_offer in database_offers: 128 129 if new_offer.offer_name == old_offer.offer_name: 130 flag = True 131 if new_offer.price != old_offer.price: 132 flag_price = True 133 offer_id = old_offer.offer_id 134 135 if flag: 136 print('ALREADY IN DATABASE') 137 print(new_offer) 138 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 139 if flag_price: 140 print('PRICE CHANGED!') # CHANGE PRICE 141 print('offer id: ' + str(offer_id)) 142 headers = {'Content-type': 'application/json'} 143 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 144 headers=headers) 145 else: 146 print('ADDED') # ADD OFFER 147 print(new_offer) 148 headers = {'Content-type': 'application/json'} 149 requests.post('http://localhost:8080/phoneoffer/addoffer', 150 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 151 152 print('------------------------------------') 116 153 117 154 for old_offer in database_offers: 155 flag = False 156 for new_offer in new_offers: 157 if old_offer.offer_name == new_offer.offer_name: 158 flag = True 118 159 119 if new_offer.offer_name == old_offer.offer_name: 120 flag = True 121 if new_offer.price != old_offer.price: 122 flag_price = True 123 offer_id = old_offer.offer_id 160 if not flag: 161 print('OFFER DELETED') 162 print(old_offer) 163 # DELETE OFFER 164 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 165 except Exception: 166 traceback.print_exc() 167 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 168 ' VALUES (%s, %s, %s);' 169 insert_value = (offer_shop, last_updated, 'failed') 170 cur.execute(insert_script, insert_value) 171 db_connection.commit() 172 cur.close() 173 db_connection.close() 174 else: 175 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 176 ' VALUES (%s, %s, %s);' 177 insert_value = (offer_shop, last_updated, 'success') 178 cur.execute(insert_script, insert_value) 179 db_connection.commit() 180 cur.close() 181 db_connection.close() 124 182 125 if flag:126 print('ALREADY IN DATABASE')127 print(new_offer)128 # if it's already in database, check PRICE and if it's changed, change it !!!!!!129 if flag_price:130 print('PRICE CHANGED!') # CHANGE PRICE131 print('offer id: ' + str(offer_id))132 headers = {'Content-type': 'application/json'}133 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price),134 headers=headers)135 else:136 print('ADDED') # ADD OFFER137 print(new_offer)138 headers = {'Content-type': 'application/json'}139 requests.post('http://localhost:8080/phoneoffer/addoffer',140 headers=headers, data=json.dumps(new_offer.__dict__, default=str))141 142 print('------------------------------------')143 144 for old_offer in database_offers:145 flag = False146 for new_offer in new_offers:147 if old_offer.offer_name == new_offer.offer_name:148 flag = True149 150 if not flag:151 print('OFFER DELETED')152 print(old_offer)153 # DELETE OFFER154 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id))155 -
phonelux_scrappers/scrappers/neptun_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 19 20 is_validated = False 20 21 21 # Neptun phone offers that are already in database 22 # Call to read the configuration file and connect to database 23 cinfo = config_read.get_databaseconfig("../postgresdb.config") 24 db_connection = psycopg2.connect( 25 database=cinfo[0], 26 host=cinfo[1], 27 user=cinfo[2], 28 password=cinfo[3] 29 ) 30 cur = db_connection.cursor() 22 31 23 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/neptun').text)) 32 try: 33 # Neptun phone offers that are already in database 34 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/neptun').text)) 24 35 25 database_offers = []36 database_offers = [] 26 37 27 for offer in offers:28 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],29 offer['ram_memory'],30 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],31 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],32 offer['image_url'],33 offer['offer_url'], offer['last_updated'], offer['is_validated'],34 offer['offer_description'],35 offer['offer_shop_code'])36 database_offers.append(phoneOffer)38 for offer in offers: 39 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 40 offer['ram_memory'], 41 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 42 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 43 offer['image_url'], 44 offer['offer_url'], offer['last_updated'], offer['is_validated'], 45 offer['offer_description'], 46 offer['offer_shop_code']) 47 database_offers.append(phoneOffer) 37 48 38 new_offers = []49 new_offers = [] 39 50 40 for i in range(1, 11):41 neptun_url = 'https://www.neptun.mk/mobilni_telefoni.nspx?page=' + str(i)51 for i in range(1, 11): 52 neptun_url = 'https://www.neptun.mk/mobilni_telefoni.nspx?page=' + str(i) 42 53 43 # selenium is used because of the dynamic content of the page44 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver')45 driver1.get(neptun_url)46 neptun_html = driver1.page_source54 # selenium is used because of the dynamic content of the page 55 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 56 driver1.get(neptun_url) 57 neptun_html = driver1.page_source 47 58 48 # closing the driver so the safari instance can pair with another webdriver session49 driver1.close()50 51 # response1 = requests.get(neptun_url)52 soup1 = BeautifulSoup(neptun_html, 'html.parser')53 54 phones = soup1.find('div', {'id': 'mainContainer'}).find('div',55 {'class': 'col-lg-9 col-md-9 col-sm-8 col-fix-main'}) \56 .find_all('div', {'class': 'ng-scope product-list-item-grid'})57 58 for phone in phones:59 offer_url = 'https://www.neptun.mk' + phone.find('a').get('href')60 offer_name = phone.find('a').find('h2').get_text().replace('MOB.TEL.', '').strip()61 brand = offer_name.split(' ')[0].strip().capitalize()62 image_url = 'https://www.neptun.mk' + phone.find('a').find('div', {'class': 'row'}).find('img').get('src')63 price = int(64 phone.find('div', {'class': 'col-sm-12 static'}).find('div', {'class': 'product-list-item__prices pt35'})65 .find('div', {'class': 'row'}).find('div', {'class': 'newPriceModel'}) \66 .find('span', {'class': 'product-price__amount--value ng-binding'}).get_text().replace('.', ''))67 68 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver')69 driver1.get(offer_url)70 offer_html = driver1.page_source71 59 # closing the driver so the safari instance can pair with another webdriver session 72 60 driver1.close() 73 61 74 soup2 = BeautifulSoup(offer_html, 'html.parser') 62 # response1 = requests.get(neptun_url) 63 soup1 = BeautifulSoup(neptun_html, 'html.parser') 75 64 76 offer_shop_code = soup2.find('div', {'ng-if': 'showProductDetails'}) \77 .find('div', {'class': 'product-details-first-row'}).find('span', {78 'ng-bind': 'model.CodeNumber'}).get_text().strip()65 phones = soup1.find('div', {'id': 'mainContainer'}).find('div', 66 {'class': 'col-lg-9 col-md-9 col-sm-8 col-fix-main'}) \ 67 .find_all('div', {'class': 'ng-scope product-list-item-grid'}) 79 68 80 specifications_table = \ 81 soup2.find('div', {'id': 'mainContainer'}).find('div', {'ng-if': 'showProductDetails'}).find_all('ul')[-1] 82 specifications = specifications_table.get_text(separator='\n').strip().split("\n") 69 for phone in phones: 70 offer_url = 'https://www.neptun.mk' + phone.find('a').get('href') 71 offer_name = phone.find('a').find('h2').get_text().replace('MOB.TEL.', '').strip() 72 brand = offer_name.split(' ')[0].strip().capitalize() 73 image_url = 'https://www.neptun.mk' + phone.find('a').find('div', {'class': 'row'}).find('img').get('src') 74 price = int( 75 phone.find('div', {'class': 'col-sm-12 static'}).find('div', {'class': 'product-list-item__prices pt35'}) 76 .find('div', {'class': 'row'}).find('div', {'class': 'newPriceModel'}) \ 77 .find('span', {'class': 'product-price__amount--value ng-binding'}).get_text().replace('.', '')) 83 78 84 offer_description = specifications_table.get_text(separator='\n').strip() 79 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 80 driver1.get(offer_url) 81 offer_html = driver1.page_source 82 # closing the driver so the safari instance can pair with another webdriver session 83 driver1.close() 85 84 86 back_camera = None 87 operating_system = None 88 chipset = None 89 battery = None 90 ram_memory = None 91 rom_memory = None 92 cpu = None 93 front_camera = None 94 color = None 85 soup2 = BeautifulSoup(offer_html, 'html.parser') 95 86 96 for specification in specifications:97 if 'Батерија:' in specification:98 battery = specification.split('Батерија:')[1]87 offer_shop_code = soup2.find('div', {'ng-if': 'showProductDetails'}) \ 88 .find('div', {'class': 'product-details-first-row'}).find('span', { 89 'ng-bind': 'model.CodeNumber'}).get_text().strip() 99 90 100 if 'CPU:' in specification: 101 cpu = specification.split('CPU:')[1] 91 specifications_table = \ 92 soup2.find('div', {'id': 'mainContainer'}).find('div', {'ng-if': 'showProductDetails'}).find_all('ul')[-1] 93 specifications = specifications_table.get_text(separator='\n').strip().split("\n") 102 94 103 if 'Chipset:' in specification: 104 chipset = specification.split('Chipset:')[1] 95 offer_description = specifications_table.get_text(separator='\n').strip() 105 96 106 if 'RAM Меморија:' in specification: 107 ram_memory = specification.split('RAM Меморија:')[1] 108 continue 97 back_camera = None 98 operating_system = None 99 chipset = None 100 battery = None 101 ram_memory = None 102 rom_memory = None 103 cpu = None 104 front_camera = None 105 color = None 109 106 110 if 'ROM Меморија:' in specification:111 rom_memory = specification.split('ROM Меморија:')[1]112 continue107 for specification in specifications: 108 if 'Батерија:' in specification: 109 battery = specification.split('Батерија:')[1] 113 110 114 if 'ROM:' in specification:115 rom_memory = specification.split('ROM:')[1]111 if 'CPU:' in specification: 112 cpu = specification.split('CPU:')[1] 116 113 117 if 'RAM:' in specification:118 ram_memory = specification.split('RAM:')[1]114 if 'Chipset:' in specification: 115 chipset = specification.split('Chipset:')[1] 119 116 120 if 'iOS' in specification or 'Android' in specification: 121 operating_system = specification 117 if 'RAM Меморија:' in specification: 118 ram_memory = specification.split('RAM Меморија:')[1] 119 continue 122 120 123 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 124 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 125 image_url, 126 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 121 if 'ROM Меморија:' in specification: 122 rom_memory = specification.split('ROM Меморија:')[1] 123 continue 127 124 128 for new_offer in new_offers: 129 flag = False 130 flag_price = False 131 offer_id = None 125 if 'ROM:' in specification: 126 rom_memory = specification.split('ROM:')[1] 127 128 if 'RAM:' in specification: 129 ram_memory = specification.split('RAM:')[1] 130 131 if 'iOS' in specification or 'Android' in specification: 132 operating_system = specification 133 134 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 135 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 136 image_url, 137 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 138 139 for new_offer in new_offers: 140 flag = False 141 flag_price = False 142 offer_id = None 143 144 for old_offer in database_offers: 145 146 if new_offer.offer_shop_code == old_offer.offer_shop_code: 147 flag = True 148 if new_offer.price != old_offer.price: 149 flag_price = True 150 offer_id = old_offer.offer_id 151 152 if flag: 153 # print('ALREADY IN DATABASE') 154 # print(new_offer) 155 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 156 if flag_price: 157 print('PRICE CHANGED!') # CHANGE PRICE 158 print('offer id: ' + str(offer_id)) 159 headers = {'Content-type': 'application/json'} 160 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 161 headers=headers) 162 else: 163 print('ADDED') # ADD OFFER 164 print(new_offer) 165 headers = {'Content-type': 'application/json'} 166 requests.post('http://localhost:8080/phoneoffer/addoffer', 167 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 168 169 print('------------------------------------') 132 170 133 171 for old_offer in database_offers: 172 flag = False 173 for new_offer in new_offers: 174 if old_offer.offer_shop_code == new_offer.offer_shop_code: 175 flag = True 134 176 135 if new_offer.offer_shop_code == old_offer.offer_shop_code: 136 flag = True 137 if new_offer.price != old_offer.price: 138 flag_price = True 139 offer_id = old_offer.offer_id 140 141 if flag: 142 # print('ALREADY IN DATABASE') 143 # print(new_offer) 144 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 145 if flag_price: 146 print('PRICE CHANGED!') # CHANGE PRICE 147 print('offer id: ' + str(offer_id)) 148 headers = {'Content-type': 'application/json'} 149 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 150 headers=headers) 151 else: 152 print('ADDED') # ADD OFFER 153 print(new_offer) 154 headers = {'Content-type': 'application/json'} 155 requests.post('http://localhost:8080/phoneoffer/addoffer', 156 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 157 158 print('------------------------------------') 159 160 for old_offer in database_offers: 161 flag = False 162 for new_offer in new_offers: 163 if old_offer.offer_shop_code == new_offer.offer_shop_code: 164 flag = True 165 166 if not flag: 167 print('OFFER DELETED') 168 print(old_offer) 169 # DELETE OFFER 170 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 177 if not flag: 178 print('OFFER DELETED') 179 print(old_offer) 180 # DELETE OFFER 181 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 182 except Exception: 183 traceback.print_exc() 184 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 185 ' VALUES (%s, %s, %s);' 186 insert_value = (offer_shop, last_updated, 'failed') 187 cur.execute(insert_script, insert_value) 188 db_connection.commit() 189 cur.close() 190 db_connection.close() 191 else: 192 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 193 ' VALUES (%s, %s, %s);' 194 insert_value = (offer_shop, last_updated, 'success') 195 cur.execute(insert_script, insert_value) 196 db_connection.commit() 197 cur.close() 198 db_connection.close() -
phonelux_scrappers/scrappers/outputfile.txt
rffd50db r47f4eaf 1 ADDED2 {'offer_shop': 'Mobile Zone', 'offer_name': 'Apple iPhone 14 Pro', 'price': 95499, 'ram_memory': None, 'rom_memory': '128GB', 'color': 'Златна, Розева, Сива, Црна', 'front_camera': '12MP', 'back_camera': '48 Mp + 12 Mp + 12 Mp', 'chipset': None, 'battery': '3200mAh', 'operating_system': None, 'cpu': None, 'image_url': 'https://i0.wp.com/mobilezone.mk/wp-content/uploads/2022/09/14-pro-silver.png?resize=600%2C600&ssl=1', 'offer_url': 'https://mobilezone.mk/produkti/iphone-14-pro/', 'last_updated': datetime.date(2022, 10, 1), 'is_validated': False, 'offer_description': None, 'offer_shop_code': None}3 ------------------------------------4 OFFER DELETED5 {'offer_id': 1179, 'offer_shop': 'Mobile Zone', 'offer_name': 'Samsung s20 FE', 'price': 24699, 'ram_memory': None, 'rom_memory': '128GB', 'color': 'Сина', 'front_camera': None, 'back_camera': None, 'chipset': None, 'battery': None, 'operating_system': None, 'cpu': None, 'image_url': 'https://i2.wp.com/mobilezone.mk/wp-content/uploads/2022/03/Samsung-Galaxy-S20-FE-blue.png?resize=512%2C600&ssl=1', 'offer_url': 'https://mobilezone.mk/produkti/samsung-s20-fe/', 'last_updated': '2022-07-29T22:00:00.000+00:00', 'is_validated': False, 'offer_description': None, 'offer_shop_code': None}6 OFFER DELETED7 {'offer_id': 1181, 'offer_shop': 'Mobile Zone', 'offer_name': 'Samsung Z Flip3 5G', 'price': 39999, 'ram_memory': None, 'rom_memory': '128GB', 'color': 'Црна', 'front_camera': None, 'back_camera': None, 'chipset': None, 'battery': None, 'operating_system': None, 'cpu': None, 'image_url': 'https://i2.wp.com/mobilezone.mk/wp-content/uploads/2022/03/11.png?resize=600%2C600&ssl=1', 'offer_url': 'https://mobilezone.mk/produkti/samsung-z-flip3-5g/', 'last_updated': '2022-07-29T22:00:00.000+00:00', 'is_validated': False, 'offer_description': None, 'offer_shop_code': None}8 OFFER DELETED9 {'offer_id': 1180, 'offer_shop': 'Mobile Zone', 'offer_name': 'Samsung S21 FE 5G', 'price': 30899, 'ram_memory': None, 'rom_memory': '128GB', 'color': 'Зелена, Црна', 'front_camera': None, 'back_camera': None, 'chipset': None, 'battery': None, 'operating_system': None, 'cpu': None, 'image_url': 'https://i1.wp.com/mobilezone.mk/wp-content/uploads/2022/03/5g.jpg?resize=600%2C600&ssl=1', 'offer_url': 'https://mobilezone.mk/produkti/samsung-s21-fe-5g/', 'last_updated': '2022-07-29T22:00:00.000+00:00', 'is_validated': False, 'offer_description': None, 'offer_shop_code': None} -
phonelux_scrappers/scrappers/setec_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 17 18 is_validated = False 18 19 19 # Setec phone offers that are already in database 20 # Call to read the configuration file and connect to database 21 cinfo = config_read.get_databaseconfig("../postgresdb.config") 22 db_connection = psycopg2.connect( 23 database=cinfo[0], 24 host=cinfo[1], 25 user=cinfo[2], 26 password=cinfo[3] 27 ) 28 cur = db_connection.cursor() 20 29 21 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/setec').text)) 30 try: 31 # Setec phone offers that are already in database 32 offers = json.loads(unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/setec').text)) 22 33 23 database_offers = []34 database_offers = [] 24 35 25 for offer in offers:26 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],27 offer['ram_memory'],28 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],29 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],30 offer['image_url'],31 offer['offer_url'], offer['last_updated'], offer['is_validated'],32 offer['offer_description'],33 offer['offer_shop_code'])34 database_offers.append(phoneOffer)36 for offer in offers: 37 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 38 offer['ram_memory'], 39 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 40 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 41 offer['image_url'], 42 offer['offer_url'], offer['last_updated'], offer['is_validated'], 43 offer['offer_description'], 44 offer['offer_shop_code']) 45 database_offers.append(phoneOffer) 35 46 36 new_offers = []47 new_offers = [] 37 48 38 for i in range(1, 9):39 setec_url = 'https://setec.mk/index.php?route=product/category&path=10066_10067&page=' + str(i)49 for i in range(1, 9): 50 setec_url = 'https://setec.mk/index.php?route=product/category&path=10066_10067&page=' + str(i) 40 51 41 response1 = requests.get(setec_url)42 soup1 = BeautifulSoup(response1.content, 'html.parser')52 response1 = requests.get(setec_url) 53 soup1 = BeautifulSoup(response1.content, 'html.parser') 43 54 44 phones = soup1.find('div', {'id': 'mfilter-content-container'}) \45 .find_all('div', {'class': 'col-sm-4 col-xs-6'})55 phones = soup1.find('div', {'id': 'mfilter-content-container'}) \ 56 .find_all('div', {'class': 'col-sm-4 col-xs-6'}) 46 57 47 for phone in phones:48 offer_url = phone.find('div', {'class': 'left'}).find('a').get('href')49 image_url = phone.find('div', {'class': 'left'}).find('a').find('img').get('src')50 offer_name = phone.find('div', {'class': 'right'}).find('div', {'class': 'name'}).find('a').get_text().strip()51 brand = offer_name.split(' ')[0]58 for phone in phones: 59 offer_url = phone.find('div', {'class': 'left'}).find('a').get('href') 60 image_url = phone.find('div', {'class': 'left'}).find('a').find('img').get('src') 61 offer_name = phone.find('div', {'class': 'right'}).find('div', {'class': 'name'}).find('a').get_text().strip() 62 brand = offer_name.split(' ')[0] 52 63 53 back_camera = None54 operating_system = None55 chipset = None56 battery = None57 ram_memory = None58 rom_memory = None59 cpu = None60 front_camera = None61 color = None64 back_camera = None 65 operating_system = None 66 chipset = None 67 battery = None 68 ram_memory = None 69 rom_memory = None 70 cpu = None 71 front_camera = None 72 color = None 62 73 63 if 'Cable' in offer_name or 'AirTag' in offer_name:64 continue74 if 'Cable' in offer_name or 'AirTag' in offer_name: 75 continue 65 76 66 if brand not in offer_name:67 offer_name = brand + " " + offer_name77 if brand not in offer_name: 78 offer_name = brand + " " + offer_name 68 79 69 offer_shop_code = phone.find('div', {'class': 'right'}) \70 .find('div', {'class': 'shifra'}).get_text().replace('Шифра:', '').strip()80 offer_shop_code = phone.find('div', {'class': 'right'}) \ 81 .find('div', {'class': 'shifra'}).get_text().replace('Шифра:', '').strip() 71 82 72 price_tag = phone.find('div', {'class': 'right'}).find('div', {'class': 'price'}). \73 find('div', {'class': 'category-price-redovna'}).find('span', {'class': 'price-old-new'})83 price_tag = phone.find('div', {'class': 'right'}).find('div', {'class': 'price'}). \ 84 find('div', {'class': 'category-price-redovna'}).find('span', {'class': 'price-old-new'}) 74 85 75 if price_tag is None:76 price_tag = phone.find('div', {'class': 'right'}).find('div', {'class': 'price'}). \77 find('div', {'class': 'category-price-redovna'}).find('span', {'class': 'cena_za_kesh'})86 if price_tag is None: 87 price_tag = phone.find('div', {'class': 'right'}).find('div', {'class': 'price'}). \ 88 find('div', {'class': 'category-price-redovna'}).find('span', {'class': 'cena_za_kesh'}) 78 89 79 price = int(price_tag.get_text().replace('Ден.', '').replace(',', '').strip())90 price = int(price_tag.get_text().replace('Ден.', '').replace(',', '').strip()) 80 91 81 response2 = requests.get(offer_url)82 soup2 = BeautifulSoup(response2.content, 'html.parser')92 response2 = requests.get(offer_url) 93 soup2 = BeautifulSoup(response2.content, 'html.parser') 83 94 84 offer_description = soup2.find('div', {'id': 'tab-description'}).get_text(separator='\n')95 offer_description = soup2.find('div', {'id': 'tab-description'}).get_text(separator='\n') 85 96 86 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory,87 color, front_camera, back_camera, chipset, battery, operating_system, cpu,88 image_url,89 offer_url, last_updated, is_validated, offer_description, offer_shop_code))97 new_offers.append(PhoneOffer(offer_shop, offer_name, price, ram_memory, rom_memory, 98 color, front_camera, back_camera, chipset, battery, operating_system, cpu, 99 image_url, 100 offer_url, last_updated, is_validated, offer_description, offer_shop_code)) 90 101 91 for new_offer in new_offers: 92 flag = False 93 flag_price = False 94 offer_id = None 102 for new_offer in new_offers: 103 flag = False 104 flag_price = False 105 offer_id = None 106 107 for old_offer in database_offers: 108 109 if new_offer.offer_shop_code == old_offer.offer_shop_code: 110 flag = True 111 if new_offer.price != old_offer.price: 112 flag_price = True 113 offer_id = old_offer.offer_id 114 115 if flag: 116 # print('ALREADY IN DATABASE') 117 # print(new_offer) 118 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 119 if flag_price: 120 print('PRICE CHANGED!') # CHANGE PRICE 121 print('offer id: ' + str(offer_id)) 122 headers = {'Content-type': 'application/json'} 123 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 124 headers=headers) 125 else: 126 print('ADDED') # ADD OFFER 127 print(new_offer) 128 headers = {'Content-type': 'application/json'} 129 requests.post('http://localhost:8080/phoneoffer/addoffer', 130 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 131 132 print('------------------------------------') 95 133 96 134 for old_offer in database_offers: 135 flag = False 136 for new_offer in new_offers: 137 if old_offer.offer_shop_code == new_offer.offer_shop_code: 138 flag = True 97 139 98 if new_offer.offer_shop_code == old_offer.offer_shop_code: 99 flag = True 100 if new_offer.price != old_offer.price: 101 flag_price = True 102 offer_id = old_offer.offer_id 103 104 if flag: 105 # print('ALREADY IN DATABASE') 106 # print(new_offer) 107 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 108 if flag_price: 109 print('PRICE CHANGED!') # CHANGE PRICE 110 print('offer id: ' + str(offer_id)) 111 headers = {'Content-type': 'application/json'} 112 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 113 headers=headers) 114 else: 115 print('ADDED') # ADD OFFER 116 print(new_offer) 117 headers = {'Content-type': 'application/json'} 118 requests.post('http://localhost:8080/phoneoffer/addoffer', 119 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 120 121 print('------------------------------------') 122 123 for old_offer in database_offers: 124 flag = False 125 for new_offer in new_offers: 126 if old_offer.offer_shop_code == new_offer.offer_shop_code: 127 flag = True 128 129 if not flag: 130 print('OFFER DELETED') 131 print(old_offer) 132 # DELETE OFFER 133 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 140 if not flag: 141 print('OFFER DELETED') 142 print(old_offer) 143 # DELETE OFFER 144 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 145 except Exception: 146 traceback.print_exc() 147 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 148 ' VALUES (%s, %s, %s);' 149 insert_value = (offer_shop, last_updated, 'failed') 150 cur.execute(insert_script, insert_value) 151 db_connection.commit() 152 cur.close() 153 db_connection.close() 154 else: 155 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 156 ' VALUES (%s, %s, %s);' 157 insert_value = (offer_shop, last_updated, 'success') 158 cur.execute(insert_script, insert_value) 159 db_connection.commit() 160 cur.close() 161 db_connection.close() -
phonelux_scrappers/scrappers/tehnomarket_scrapper.py
rffd50db r47f4eaf 1 1 import json 2 import traceback 2 3 import unicodedata 3 4 from datetime import datetime … … 76 77 77 78 78 # Tehnomarket phone offers that are already in database 79 # Call to read the configuration file and connect to database 80 cinfo = config_read.get_databaseconfig("../postgresdb.config") 81 db_connection = psycopg2.connect( 82 database=cinfo[0], 83 host=cinfo[1], 84 user=cinfo[2], 85 password=cinfo[3] 86 ) 87 cur = db_connection.cursor() 79 88 80 offers = json.loads( 81 unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/tehnomarket').text)) 89 try: 90 # Tehnomarket phone offers that are already in database 91 offers = json.loads( 92 unicodedata.normalize('NFKD', requests.get('http://localhost:8080/phoneoffer/shop/tehnomarket').text)) 82 93 83 database_offers = []94 database_offers = [] 84 95 85 for offer in offers:86 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'],87 offer['ram_memory'],88 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'],89 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'],90 offer['image_url'],91 offer['offer_url'], offer['last_updated'], offer['is_validated'],92 offer['offer_description'],93 offer['offer_shop_code'])94 database_offers.append(phoneOffer)96 for offer in offers: 97 phoneOffer = PhoneOffer(offer['id'], offer['offer_shop'], offer['offer_name'], offer['price'], 98 offer['ram_memory'], 99 offer['rom_memory'], offer['color'], offer['front_camera'], offer['back_camera'], 100 offer['chipset'], offer['battery'], offer['operating_system'], offer['cpu'], 101 offer['image_url'], 102 offer['offer_url'], offer['last_updated'], offer['is_validated'], 103 offer['offer_description'], 104 offer['offer_shop_code']) 105 database_offers.append(phoneOffer) 95 106 96 new_offers = []107 new_offers = [] 97 108 98 for i in range(1, 6):99 tehnomarket_url = 'https://tehnomarket.com.mk/category/4109/mobilni-telefoni#page/' + str(i)100 # print(anhoch_url)109 for i in range(1, 6): 110 tehnomarket_url = 'https://tehnomarket.com.mk/category/4109/mobilni-telefoni#page/' + str(i) 111 # print(anhoch_url) 101 112 102 # selenium is used because of the dynamic content of the page103 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver')104 driver1.get(tehnomarket_url)113 # selenium is used because of the dynamic content of the page 114 driver1 = webdriver.Safari(executable_path='/usr/bin/safaridriver') 115 driver1.get(tehnomarket_url) 105 116 106 scrape_function(driver1, i, new_offers)117 scrape_function(driver1, i, new_offers) 107 118 108 # closing the driver so the safari instance can pair with another webdriver session109 driver1.close()119 # closing the driver so the safari instance can pair with another webdriver session 120 driver1.close() 110 121 111 for new_offer in new_offers: 112 flag = False 113 flag_price = False 114 offer_id = None 122 for new_offer in new_offers: 123 flag = False 124 flag_price = False 125 offer_id = None 126 127 for old_offer in database_offers: 128 129 if new_offer.offer_shop_code == old_offer.offer_shop_code: 130 flag = True 131 if new_offer.price != old_offer.price: 132 flag_price = True 133 offer_id = old_offer.offer_id 134 135 if flag: 136 # print('ALREADY IN DATABASE') 137 # print(new_offer) 138 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 139 if flag_price: 140 print('PRICE CHANGED!') # CHANGE PRICE 141 print('offer id: ' + str(offer_id)) 142 headers = {'Content-type': 'application/json'} 143 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 144 headers=headers) 145 else: 146 print('ADDED') # ADD OFFER 147 print(new_offer) 148 headers = {'Content-type': 'application/json'} 149 requests.post('http://localhost:8080/phoneoffer/addoffer', 150 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 151 152 print('------------------------------------') 115 153 116 154 for old_offer in database_offers: 155 flag = False 156 for new_offer in new_offers: 157 if old_offer.offer_shop_code == new_offer.offer_shop_code: 158 flag = True 117 159 118 if new_offer.offer_shop_code == old_offer.offer_shop_code: 119 flag = True 120 if new_offer.price != old_offer.price: 121 flag_price = True 122 offer_id = old_offer.offer_id 123 124 if flag: 125 # print('ALREADY IN DATABASE') 126 # print(new_offer) 127 # if it's already in database, check PRICE and if it's changed, change it !!!!!! 128 if flag_price: 129 print('PRICE CHANGED!') # CHANGE PRICE 130 print('offer id: ' + str(offer_id)) 131 headers = {'Content-type': 'application/json'} 132 requests.put('http://localhost:8080/phoneoffer/' + str(offer_id) + '/changeprice/' + str(new_offer.price), 133 headers=headers) 134 else: 135 print('ADDED') # ADD OFFER 136 print(new_offer) 137 headers = {'Content-type': 'application/json'} 138 requests.post('http://localhost:8080/phoneoffer/addoffer', 139 headers=headers, data=json.dumps(new_offer.__dict__, default=str)) 140 141 print('------------------------------------') 142 143 for old_offer in database_offers: 144 flag = False 145 for new_offer in new_offers: 146 if old_offer.offer_shop_code == new_offer.offer_shop_code: 147 flag = True 148 149 if not flag: 150 print('OFFER DELETED') 151 print(old_offer) 152 # DELETE OFFER 153 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 160 if not flag: 161 print('OFFER DELETED') 162 print(old_offer) 163 # DELETE OFFER 164 requests.delete('http://localhost:8080/phoneoffer/deleteoffer/' + str(old_offer.offer_id)) 165 except Exception: 166 traceback.print_exc() 167 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 168 ' VALUES (%s, %s, %s);' 169 insert_value = ('Tehnomarket', datetime.now().date(), 'failed') 170 cur.execute(insert_script, insert_value) 171 db_connection.commit() 172 cur.close() 173 db_connection.close() 174 else: 175 insert_script = 'INSERT INTO scrapper_info (store, recieved_at, status)' \ 176 ' VALUES (%s, %s, %s);' 177 insert_value = ('Tehnomarket', datetime.now().date(), 'success') 178 cur.execute(insert_script, insert_value) 179 db_connection.commit() 180 cur.close() 181 db_connection.close()
Note:
See TracChangeset
for help on using the changeset viewer.