├── .gitignore ├── .nojekyll ├── 404.html ├── CNAME ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── SUMMARY.md ├── asset ├── docsify-apachecn-footer.js ├── docsify-baidu-push.js ├── docsify-baidu-stat.js ├── docsify-clicker.js ├── docsify-cnzz.js ├── docsify-copy-code.min.js ├── docsify.min.js ├── prism-darcula.css ├── prism-python.min.js ├── search.min.js ├── style.css └── vue.css ├── docs ├── 10.md ├── 11.md ├── 12.md ├── 13.md ├── 14.md ├── 15.md ├── 16.md ├── 17.md ├── 18.md ├── 19.md ├── 2.md ├── 20.md ├── 21.md ├── 22.md ├── 23.md ├── 24.md ├── 25.md ├── 26.md ├── 27.md ├── 28.md ├── 29.md ├── 3.md ├── 30.md ├── 31.md ├── 32.md ├── 33.md ├── 34.md ├── 35.md ├── 36.md ├── 37.md ├── 38.md ├── 39.md ├── 4.md ├── 40.md ├── 41.md ├── 42.md ├── 43.md ├── 44.md ├── 45.md ├── 46.md ├── 47.md ├── 48.md ├── 49.md ├── 5.md ├── 50.md ├── 6.md ├── 7.md ├── 8.md ├── 9.md ├── img │ ├── 6d09274a6a0eadb4fac81ff1bd508248.jpg │ ├── d3df2a33256732c3bb420ea930dbda9a.jpg │ ├── d74a68f3540ed16e6533632095e18fc1.jpg │ ├── ebf6f0b54b0530b158ca080658e3473d.jpg │ └── fca494eacecdaeee595ae572e32d80d2.jpg └── index.md ├── index.html └── update.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/.nojekyll -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | scrapy.apachecn.org -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | > 请您勇敢地去翻译和改进翻译。虽然我们追求卓越,但我们并不要求您做到十全十美,因此请不要担心因为翻译上犯错——在大部分情况下,我们的服务器已经记录所有的翻译,因此您不必担心会因为您的失误遭到无法挽回的破坏。(改编自维基百科) 4 | 5 | 负责人: 6 | 7 | + [简杨君](https://github.com/yangjiada):823139365 8 | 9 | ## 章节列表 10 | 11 | + [简介](docs/index.md) 12 | + [第一步](docs/2.md) 13 | + [Scrapy at a glance](docs/3.md) 14 | + [安装指南](docs/4.md) 15 | + [Scrapy 教程](docs/5.md) 16 | + [实例](docs/6.md) 17 | + [基本概念](docs/7.md) 18 | + [命令行工具](docs/8.md) 19 | + [Spider](docs/9.md) 20 | + [选择器](docs/10.md) 21 | + [项目](docs/11.md) 22 | + [项目加载器](docs/12.md) 23 | + [Scrapy shell](docs/13.md) 24 | + [项目管道](docs/14.md) 25 | + [Feed 导出](docs/15.md) 26 | + [请求和响应](docs/16.md) 27 | + [链接提取器](docs/17.md) 28 | + [设置](docs/18.md) 29 | + [例外情况](docs/19.md) 30 | + [内置服务](docs/20.md) 31 | + [Logging](docs/21.md) 32 | + [统计数据集合](docs/22.md) 33 | + [发送电子邮件](docs/23.md) 34 | + [远程登录控制台](docs/24.md) 35 | + [Web服务](docs/25.md) 36 | + [解决具体问题](docs/26.md) 37 | + [常见问题](docs/27.md) 38 | + [调试spiders](docs/28.md) 39 | + [Spider 合约](docs/29.md) 40 | + [常用做法](docs/30.md) 41 | + [通用爬虫](docs/31.md) 42 | + [使用浏览器的开发人员工具进行抓取](docs/32.md) 43 | + [调试内存泄漏](docs/33.md) 44 | + [下载和处理文件和图像](docs/34.md) 45 | + [部署 Spider](docs/35.md) 46 | + [AutoThrottle 扩展](docs/36.md) 47 | + [Benchmarking](docs/37.md) 48 | + [作业:暂停和恢复爬行](docs/38.md) 49 | + [延伸 Scrapy](docs/39.md) 50 | + [体系结构概述](docs/40.md) 51 | + [下载器中间件](docs/41.md) 52 | + [Spider 中间件](docs/42.md) 53 | + [扩展](docs/43.md) 54 | + [核心API](docs/44.md) 55 | + [信号](docs/45.md) 56 | + [条目导出器](docs/46.md) 57 | + [其余所有](docs/47.md) 58 | + [发行说明](docs/48.md) 59 | + [为 Scrapy 贡献](docs/49.md) 60 | + [版本控制和API稳定性](docs/50.md) 61 | 62 | ## 流程 63 | 64 | ### 一、认领 65 | 66 | 首先查看[整体进度](https://github.com/apachecn/scrapy-doc-zh/issues/1),确认没有人认领了你想认领的章节。 67 | 68 | 然后回复 ISSUE,注明“章节 + QQ 号”(一定要留 QQ)。 69 | 70 | ### 二、校对 71 | 72 | 需要校对: 73 | 74 | 1. 语法 75 | 2. 术语使用 76 | 3. 文档格式 77 | 78 | 如果觉得现有翻译不好,重新翻译也是可以的。 79 | 80 | ### 三、提交 81 | 82 | + `fork` Github 项目 83 | + 将译文放在`docs`文件夹下 84 | + `push` 85 | + `pull request` 86 | 87 | 请见 [Github 入门指南](https://github.com/apachecn/kaggle/blob/master/docs/GitHub)。 88 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM httpd:2.4 2 | COPY ./ /usr/local/apache2/htdocs/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scrapy 1.6 中文文档 2 | 3 | ![](https://scrapy.org/img/scrapylogo.png) 4 | 5 | > 原文:[Scrapy 1.6 documentation](https://docs.scrapy.org/en/1.6/) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | > 9 | > 软件开发往往是这样:最开始的 90% 代码占用了开始的 90% 的开发时间;剩下 10% 代码同样需要 90% 的开发时间。——Tom Cargill 10 | 11 | * [在线阅读](https://scrapy.apachecn.org) 12 | * [在线阅读(Gitee)](https://apachecn.gitee.io/scrapy-doc-zh/) 13 | * [ApacheCN 面试求职交流群 724187166](https://jq.qq.com/?_wv=1027&k=54ujcL3) 14 | * [ApacheCN 学习资源](http://www.apachecn.org/) 15 | 16 | ## 贡献指南 17 | 18 | 项目当前处于校对阶段,请查看[贡献指南](CONTRIBUTING.md),并在[整体进度](https://github.com/apachecn/scrapy-doc-zh/issues/1)中领取任务。 19 | 20 | > 请您勇敢地去翻译和改进翻译。虽然我们追求卓越,但我们并不要求您做到十全十美,因此请不要担心因为翻译上犯错——在大部分情况下,我们的服务器已经记录所有的翻译,因此您不必担心会因为您的失误遭到无法挽回的破坏。(改编自维基百科) 21 | 22 | ## 联系方式 23 | 24 | ### 负责人 25 | 26 | + [简杨君](https://github.com/yangjiada):823139365 27 | 28 | ### 其他 29 | 30 | * 认领翻译和项目进度-地址: 31 | * 在我们的 [apachecn/scrapy-doc-zh](https://github.com/apachecn/scrapy-doc-zh) github 上提 issue. 32 | * 发邮件到 Email: `apachecn@163.com`. 33 | * 在我们的 [组织学习交流群](http://www.apachecn.org/organization/348.html) 中联系群主/管理员即可. 34 | 35 | ## 下载 36 | 37 | ### Docker 38 | 39 | ``` 40 | docker pull apachecn0/scrapy-doc-zh 41 | docker run -tid -p :80 apachecn0/scrapy-doc-zh 42 | # 访问 http://localhost:{port} 查看文档 43 | ``` 44 | 45 | ### PYPI 46 | 47 | ``` 48 | pip install scrapy-doc-zh 49 | scrapy-doc-zh 50 | # 访问 http://localhost:{port} 查看文档 51 | ``` 52 | 53 | ### NPM 54 | 55 | ``` 56 | npm install -g scrapy-doc-zh 57 | scrapy-doc-zh 58 | # 访问 http://localhost:{port} 查看文档 59 | ``` 60 | 61 | ## 赞助我们 62 | 63 | ![](http://data.apachecn.org/img/about/donate.jpg) 64 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | + [简介](docs/index.md) 2 | + [第一步](docs/2.md) 3 | + [Scrapy at a glance](docs/3.md) 4 | + [安装指南](docs/4.md) 5 | + [Scrapy 教程](docs/5.md) 6 | + [实例](docs/6.md) 7 | + [基本概念](docs/7.md) 8 | + [命令行工具](docs/8.md) 9 | + [Spider](docs/9.md) 10 | + [选择器](docs/10.md) 11 | + [项目](docs/11.md) 12 | + [项目加载器](docs/12.md) 13 | + [Scrapy shell](docs/13.md) 14 | + [项目管道](docs/14.md) 15 | + [Feed 导出](docs/15.md) 16 | + [请求和响应](docs/16.md) 17 | + [链接提取器](docs/17.md) 18 | + [设置](docs/18.md) 19 | + [例外情况](docs/19.md) 20 | + [内置服务](docs/20.md) 21 | + [Logging](docs/21.md) 22 | + [统计数据集合](docs/22.md) 23 | + [发送电子邮件](docs/23.md) 24 | + [远程登录控制台](docs/24.md) 25 | + [Web服务](docs/25.md) 26 | + [解决具体问题](docs/26.md) 27 | + [常见问题](docs/27.md) 28 | + [调试spiders](docs/28.md) 29 | + [Spider 合约](docs/29.md) 30 | + [常用做法](docs/30.md) 31 | + [通用爬虫](docs/31.md) 32 | + [使用浏览器的开发人员工具进行抓取](docs/32.md) 33 | + [调试内存泄漏](docs/33.md) 34 | + [下载和处理文件和图像](docs/34.md) 35 | + [部署 Spider](docs/35.md) 36 | + [AutoThrottle 扩展](docs/36.md) 37 | + [Benchmarking](docs/37.md) 38 | + [作业:暂停和恢复爬行](docs/38.md) 39 | + [延伸 Scrapy](docs/39.md) 40 | + [体系结构概述](docs/40.md) 41 | + [下载器中间件](docs/41.md) 42 | + [Spider 中间件](docs/42.md) 43 | + [扩展](docs/43.md) 44 | + [核心API](docs/44.md) 45 | + [信号](docs/45.md) 46 | + [条目导出器](docs/46.md) 47 | + [其余所有](docs/47.md) 48 | + [发行说明](docs/48.md) 49 | + [为 Scrapy 贡献](docs/49.md) 50 | + [版本控制和API稳定性](docs/50.md) 51 | -------------------------------------------------------------------------------- /asset/docsify-apachecn-footer.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var footer = [ 3 | '
', 4 | '
', 5 | '

我们一直在努力

', 6 | '

apachecn/scrapy-doc-zh

', 7 | '

', 8 | ' ', 9 | ' ', 10 | ' ML | ApacheCN

', 11 | '

', 12 | '
', 13 | ' ', 17 | '
', 18 | '
' 19 | ].join('\n') 20 | var plugin = function(hook) { 21 | hook.afterEach(function(html) { 22 | return html + footer 23 | }) 24 | hook.doneEach(function() { 25 | (adsbygoogle = window.adsbygoogle || []).push({}) 26 | }) 27 | } 28 | var plugins = window.$docsify.plugins || [] 29 | plugins.push(plugin) 30 | window.$docsify.plugins = plugins 31 | })() -------------------------------------------------------------------------------- /asset/docsify-baidu-push.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var plugin = function(hook) { 3 | hook.doneEach(function() { 4 | new Image().src = 5 | '//api.share.baidu.com/s.gif?r=' + 6 | encodeURIComponent(document.referrer) + 7 | "&l=" + encodeURIComponent(location.href) 8 | }) 9 | } 10 | var plugins = window.$docsify.plugins || [] 11 | plugins.push(plugin) 12 | window.$docsify.plugins = plugins 13 | })() -------------------------------------------------------------------------------- /asset/docsify-baidu-stat.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var plugin = function(hook) { 3 | hook.doneEach(function() { 4 | window._hmt = window._hmt || [] 5 | var hm = document.createElement("script") 6 | hm.src = "https://hm.baidu.com/hm.js?" + window.$docsify.bdStatId 7 | document.querySelector("article").appendChild(hm) 8 | }) 9 | } 10 | var plugins = window.$docsify.plugins || [] 11 | plugins.push(plugin) 12 | window.$docsify.plugins = plugins 13 | })() -------------------------------------------------------------------------------- /asset/docsify-cnzz.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var plugin = function(hook) { 3 | hook.doneEach(function() { 4 | var sc = document.createElement('script') 5 | sc.src = 'https://s5.cnzz.com/z_stat.php?id=' + 6 | window.$docsify.cnzzId + '&online=1&show=line' 7 | document.querySelector('article').appendChild(sc) 8 | }) 9 | } 10 | var plugins = window.$docsify.plugins || [] 11 | plugins.push(plugin) 12 | window.$docsify.plugins = plugins 13 | })() -------------------------------------------------------------------------------- /asset/docsify-copy-code.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * docsify-copy-code 3 | * v2.1.0 4 | * https://github.com/jperasmus/docsify-copy-code 5 | * (c) 2017-2019 JP Erasmus 6 | * MIT license 7 | */ 8 | !function(){"use strict";function r(o){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}!function(o,e){void 0===e&&(e={});var t=e.insertAt;if(o&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=o:c.appendChild(document.createTextNode(o))}}(".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:0}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:-100;top:50%;left:0;padding:.5em .65em;font-size:.825em;opacity:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{opacity:1;-webkit-transform:translate(-115%,-50%);transform:translate(-115%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(o,e){o.ready(function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")})}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,s){o.doneEach(function(){var o=Array.apply(null,document.querySelectorAll("pre[data-lang]")),c={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};s.config.copyCode&&Object.keys(c).forEach(function(t){var n=s.config.copyCode[t];"string"==typeof n?c[t]=n:"object"===r(n)&&Object.keys(n).some(function(o){var e=-1',''.concat(c.buttonText,""),''.concat(c.errorText,""),''.concat(c.successText,""),""].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}(); 9 | //# sourceMappingURL=docsify-copy-code.min.js.map 10 | -------------------------------------------------------------------------------- /asset/prism-darcula.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Darcula theme 3 | * 4 | * Adapted from a theme based on: 5 | * IntelliJ Darcula Theme (https://github.com/bulenkov/Darcula) 6 | * 7 | * @author Alexandre Paradis 8 | * @version 1.0 9 | */ 10 | 11 | code[class*="lang-"], 12 | pre[data-lang] { 13 | color: #a9b7c6 !important; 14 | background-color: #2b2b2b !important; 15 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 16 | direction: ltr; 17 | text-align: left; 18 | white-space: pre; 19 | word-spacing: normal; 20 | word-break: normal; 21 | line-height: 1.5; 22 | 23 | -moz-tab-size: 4; 24 | -o-tab-size: 4; 25 | tab-size: 4; 26 | 27 | -webkit-hyphens: none; 28 | -moz-hyphens: none; 29 | -ms-hyphens: none; 30 | hyphens: none; 31 | } 32 | 33 | pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, 34 | code[class*="lang-"]::-moz-selection, code[class*="lang-"] ::-moz-selection { 35 | color: inherit; 36 | background: rgba(33, 66, 131, .85); 37 | } 38 | 39 | pre[data-lang]::selection, pre[data-lang] ::selection, 40 | code[class*="lang-"]::selection, code[class*="lang-"] ::selection { 41 | color: inherit; 42 | background: rgba(33, 66, 131, .85); 43 | } 44 | 45 | /* Code blocks */ 46 | pre[data-lang] { 47 | padding: 1em; 48 | margin: .5em 0; 49 | overflow: auto; 50 | } 51 | 52 | :not(pre) > code[class*="lang-"], 53 | pre[data-lang] { 54 | background: #2b2b2b; 55 | } 56 | 57 | /* Inline code */ 58 | :not(pre) > code[class*="lang-"] { 59 | padding: .1em; 60 | border-radius: .3em; 61 | } 62 | 63 | .token.comment, 64 | .token.prolog, 65 | .token.cdata { 66 | color: #808080; 67 | } 68 | 69 | .token.delimiter, 70 | .token.boolean, 71 | .token.keyword, 72 | .token.selector, 73 | .token.important, 74 | .token.atrule { 75 | color: #cc7832; 76 | } 77 | 78 | .token.operator, 79 | .token.punctuation, 80 | .token.attr-name { 81 | color: #a9b7c6; 82 | } 83 | 84 | .token.tag, 85 | .token.tag .punctuation, 86 | .token.doctype, 87 | .token.builtin { 88 | color: #e8bf6a; 89 | } 90 | 91 | .token.entity, 92 | .token.number, 93 | .token.symbol { 94 | color: #6897bb; 95 | } 96 | 97 | .token.property, 98 | .token.constant, 99 | .token.variable { 100 | color: #9876aa; 101 | } 102 | 103 | .token.string, 104 | .token.char { 105 | color: #6a8759; 106 | } 107 | 108 | .token.attr-value, 109 | .token.attr-value .punctuation { 110 | color: #a5c261; 111 | } 112 | 113 | .token.attr-value .punctuation:first-child { 114 | color: #a9b7c6; 115 | } 116 | 117 | .token.url { 118 | color: #287bde; 119 | text-decoration: underline; 120 | } 121 | 122 | .token.function { 123 | color: #ffc66d; 124 | } 125 | 126 | .token.regex { 127 | background: #364135; 128 | } 129 | 130 | .token.bold { 131 | font-weight: bold; 132 | } 133 | 134 | .token.italic { 135 | font-style: italic; 136 | } 137 | 138 | .token.inserted { 139 | background: #294436; 140 | } 141 | 142 | .token.deleted { 143 | background: #484a4a; 144 | } 145 | 146 | code.lang-css .token.property, 147 | code.lang-css .token.property + .token.punctuation { 148 | color: #a9b7c6; 149 | } 150 | 151 | code.lang-css .token.id { 152 | color: #ffc66d; 153 | } 154 | 155 | code.lang-css .token.selector > .token.class, 156 | code.lang-css .token.selector > .token.attribute, 157 | code.lang-css .token.selector > .token.pseudo-class, 158 | code.lang-css .token.selector > .token.pseudo-element { 159 | color: #ffc66d; 160 | } -------------------------------------------------------------------------------- /asset/prism-python.min.js: -------------------------------------------------------------------------------- 1 | Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},"string-interpolation":{pattern:/(?:f|rf|fr)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:{{)*){(?!{)(?:[^{}]|{(?!{)(?:[^{}]|{(?!{)(?:[^{}])+})+})+}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|rb|br)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^\s*)@\w+(?:\.\w+)*/im,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:True|False|None)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python; -------------------------------------------------------------------------------- /asset/search.min.js: -------------------------------------------------------------------------------- 1 | !function(){var h={},f={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function l(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function p(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function u(r,e,i,o){void 0===e&&(e="");var s,n=window.marked.lexer(e),c=window.Docsify.slugify,d={};return n.forEach(function(e){if("heading"===e.type&&e.depth<=o){var n=function(e){void 0===e&&(e="");var a={};return{str:e=e&&e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(a[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:a}}(e.text),t=n.str,a=n.config;s=a.id?i.toURL(r,{id:c(a.id)}):i.toURL(r,{id:c(l(e.text))}),d[s]={slug:s,title:t,body:""}}else{if(!s)return;d[s]?d[s].body?(e.text=p(e),d[s].body+="\n"+(e.text||"")):(e.text=p(e),d[s].body=d[s].body?d[s].body+e.text:e.text):d[s]={slug:s,title:"",body:""}}}),c.clear(),d}function c(e){var r=[],i=[];Object.keys(h).forEach(function(n){i=i.concat(Object.keys(h[n]).map(function(e){return h[n][e]}))});var o=(e=e.trim()).split(/[\s\-,\\/]+/);1!==o.length&&(o=[].concat(e,o));function n(e){var n=i[e],s=0,c="",d=n.title&&n.title.trim(),p=n.body&&n.body.trim(),t=n.slug||"";if(d&&(o.forEach(function(e){var n,t=new RegExp(e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),a=-1;if(n=d?d.search(t):-1,a=p?p.search(t):-1,0<=n||0<=a){s+=0<=n?3:0<=a?2:0,a<0&&(a=0);var r,i=0;i=0==(r=a<11?0:a-10)?70:a+e.length+60,p&&i>p.length&&(i=p.length);var o="..."+l(p).substring(r,i).replace(t,function(e){return''+e+""})+"...";c+=o}}),0\n\n

'+e.title+"

\n

"+e.content+"

\n
\n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=s||'

'+m+"

",d.hideOtherSidebarContent&&(r.classList.add("hide"),i.classList.add("hide"))}function a(e){d=e}function o(e,n){var t=n.router.parse().query.s;a(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n='
\n \n
\n \n \n \n \n \n
\n
\n
\n ',t=Docsify.dom.create("div",n),a=Docsify.dom.find("aside");Docsify.dom.toggleClass(t,"search"),Docsify.dom.before(a,t)}(t),function(){var e,n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,"input"),a=Docsify.dom.find(n,".input-wrap");Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(t,"input",function(n){clearTimeout(e),e=setTimeout(function(e){return r(n.target.value.trim())},100)}),Docsify.dom.on(a,"click",function(e){"INPUT"!==e.target.tagName&&(t.value="",r())})}(),t&&setTimeout(function(e){return r(t)},500)}function s(e,n){a(e),function(e,n){var t=Docsify.dom.getNode('.search input[type="search"]');if(t)if("string"==typeof e)t.placeholder=e;else{var a=Object.keys(e).filter(function(e){return-1ul:nth-child(1) { 3 | display: none; 4 | } 5 | 6 | #main>ul:nth-child(2) { 7 | display: none; 8 | } 9 | 10 | .markdown-section h1 { 11 | margin: 3rem 0 2rem 0; 12 | } 13 | 14 | .markdown-section h2 { 15 | margin: 2rem 0 1rem; 16 | } 17 | 18 | img, 19 | pre { 20 | border-radius: 8px; 21 | } 22 | 23 | .content, 24 | .sidebar, 25 | .markdown-section, 26 | body, 27 | .search input { 28 | background-color: rgba(243, 242, 238, 1) !important; 29 | } 30 | 31 | @media (min-width:600px) { 32 | .sidebar-toggle { 33 | background-color: #f3f2ee; 34 | } 35 | } 36 | 37 | .docsify-copy-code-button { 38 | background: #f8f8f8 !important; 39 | color: #7a7a7a !important; 40 | } 41 | 42 | body { 43 | /*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/ 44 | } 45 | 46 | .markdown-section>p { 47 | font-size: 16px !important; 48 | } 49 | 50 | .markdown-section pre>code { 51 | font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important; 52 | font-size: .9rem !important; 53 | 54 | } 55 | 56 | /*.anchor span { 57 | color: rgb(66, 185, 131); 58 | }*/ 59 | 60 | section.cover h1 { 61 | margin: 0; 62 | } 63 | 64 | body>section>div.cover-main>ul>li>a { 65 | color: #42b983; 66 | } 67 | 68 | .markdown-section img { 69 | box-shadow: 7px 9px 10px #aaa !important; 70 | } 71 | 72 | 73 | pre { 74 | background-color: #f3f2ee !important; 75 | } 76 | 77 | @media (min-width:600px) { 78 | pre code { 79 | /*box-shadow: 2px 1px 20px 2px #aaa;*/ 80 | /*border-radius: 10px !important;*/ 81 | padding-left: 20px !important; 82 | } 83 | } 84 | 85 | @media (max-width:600px) { 86 | pre { 87 | padding-left: 0px !important; 88 | padding-right: 0px !important; 89 | } 90 | } 91 | 92 | .markdown-section pre { 93 | padding-left: 0 !important; 94 | padding-right: 0px !important; 95 | box-shadow: 2px 1px 20px 2px #aaa; 96 | } -------------------------------------------------------------------------------- /docs/11.md: -------------------------------------------------------------------------------- 1 | # 项目 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据。scrappyspider可以以python dicts的形式返回提取的数据。虽然方便和熟悉,但python dicts缺乏结构:很容易在字段名中输入错误或返回不一致的数据,特别是在有许多spider的大型项目中。 6 | 7 | 要定义通用输出数据格式,scrapy提供 [`Item`](#scrapy.item.Item "scrapy.item.Item") 类。 [`Item`](#scrapy.item.Item "scrapy.item.Item") 对象是用于收集抓取数据的简单容器。他们提供了一个 [dictionary-like](https://docs.python.org/2/library/stdtypes.html#dict) 具有声明可用字段的方便语法的API。 8 | 9 | 各种零碎组件使用项目提供的额外信息:导出器查看声明的字段以确定要导出的列,可以使用项目字段元数据自定义序列化。 `trackref` 跟踪项实例以帮助查找内存泄漏(请参阅 [使用调试内存泄漏 trackref](leaks.html#topics-leaks-trackrefs) 等)。 10 | 11 | ## 声明项目 12 | 13 | 使用简单的类定义语法和 [`Field`](#scrapy.item.Field "scrapy.item.Field") 物体。下面是一个例子: 14 | 15 | ```py 16 | import scrapy 17 | 18 | class Product(scrapy.Item): 19 | name = scrapy.Field() 20 | price = scrapy.Field() 21 | stock = scrapy.Field() 22 | tags = scrapy.Field() 23 | last_updated = scrapy.Field(serializer=str) 24 | 25 | ``` 26 | 27 | 注解 28 | 29 | 那些熟悉 [Django](https://www.djangoproject.com/) 会注意到 Scrapy 物品的声明类似于 [Django Models](https://docs.djangoproject.com/en/dev/topics/db/models/) 但是,由于不存在不同字段类型的概念,因此片段项要简单得多。 30 | 31 | ## 项目字段 32 | 33 | [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象用于为每个字段指定元数据。例如,用于 `last_updated` 上面示例中所示的字段。 34 | 35 | 可以为每个字段指定任何类型的元数据。对接受的值没有限制 [`Field`](#scrapy.item.Field "scrapy.item.Field") 物体。出于同样的原因,没有所有可用元数据键的引用列表。中定义的每个键 [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象可以由不同的组件使用,只有那些组件知道它。您还可以定义和使用任何其他 [`Field`](#scrapy.item.Field "scrapy.item.Field") 为了你自己的需要,也要输入你的项目。的主要目标 [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象是提供一种在一个地方定义所有字段元数据的方法。通常,行为依赖于每个字段的组件使用特定的字段键来配置该行为。您必须参考它们的文档来查看每个组件使用的元数据键。 36 | 37 | 重要的是要注意 [`Field`](#scrapy.item.Field "scrapy.item.Field") 用于声明该项的对象不会保留分配为类属性的状态。相反,可以通过 [`Item.fields`](#scrapy.item.Item.fields "scrapy.item.Item.fields") 属性。 38 | 39 | ## 处理项目 40 | 41 | 下面是一些使用项执行的常见任务的示例,使用 `Product` 项目 [declared above](#topics-items-declaring) . 您会注意到API与 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) . 42 | 43 | ### 创建项目 44 | 45 | ```py 46 | >>> product = Product(name='Desktop PC', price=1000) 47 | >>> print(product) 48 | Product(name='Desktop PC', price=1000) 49 | 50 | ``` 51 | 52 | ### 获取字段值 53 | 54 | ```py 55 | >>> product['name'] 56 | Desktop PC 57 | >>> product.get('name') 58 | Desktop PC 59 | 60 | >>> product['price'] 61 | 1000 62 | 63 | >>> product['last_updated'] 64 | Traceback (most recent call last): 65 | ... 66 | KeyError: 'last_updated' 67 | 68 | >>> product.get('last_updated', 'not set') 69 | not set 70 | 71 | >>> product['lala'] # getting unknown field 72 | Traceback (most recent call last): 73 | ... 74 | KeyError: 'lala' 75 | 76 | >>> product.get('lala', 'unknown field') 77 | 'unknown field' 78 | 79 | >>> 'name' in product # is name field populated? 80 | True 81 | 82 | >>> 'last_updated' in product # is last_updated populated? 83 | False 84 | 85 | >>> 'last_updated' in product.fields # is last_updated a declared field? 86 | True 87 | 88 | >>> 'lala' in product.fields # is lala a declared field? 89 | False 90 | 91 | ``` 92 | 93 | ### 设置字段值 94 | 95 | ```py 96 | >>> product['last_updated'] = 'today' 97 | >>> product['last_updated'] 98 | today 99 | 100 | >>> product['lala'] = 'test' # setting unknown field 101 | Traceback (most recent call last): 102 | ... 103 | KeyError: 'Product does not support field: lala' 104 | 105 | ``` 106 | 107 | ### 访问所有填充的值 108 | 109 | 要访问所有填充的值,只需使用 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) :: 110 | 111 | ```py 112 | >>> product.keys() 113 | ['price', 'name'] 114 | 115 | >>> product.items() 116 | [('price', 1000), ('name', 'Desktop PC')] 117 | 118 | ``` 119 | 120 | ### 复制项目 121 | 122 | 要复制项目,必须首先决定是要浅副本还是深副本。 123 | 124 | 如果您的物品包含 [mutable](https://docs.python.org/glossary.html#term-mutable) 值如列表或字典,一个浅拷贝将在所有不同的拷贝中保持对相同可变值的引用。 125 | 126 | 例如,如果您有一个带有标记列表的项目,并且您创建了该项目的浅副本,那么原始项目和副本都具有相同的标记列表。向其中一个项目的列表中添加标记也会将标记添加到另一个项目中。 127 | 128 | 如果这不是所需的行为,请使用深度复制。 129 | 130 | 见 [documentation of the copy module](https://docs.python.org/library/copy.html) 更多信息。 131 | 132 | 要创建项目的浅副本,可以调用 `copy()` 在现有项上 (`product2 = product.copy()` )或从现有项实例化项类 (`product2 = Product(product)` ) 133 | 134 | 要创建深度复制,请调用 `deepcopy()` 相反 (`product2 = product.deepcopy()` ) 135 | 136 | ### 其他常见任务 137 | 138 | 从项目创建听写: 139 | 140 | ```py 141 | >>> dict(product) # create a dict from all populated values 142 | {'price': 1000, 'name': 'Desktop PC'} 143 | 144 | ``` 145 | 146 | 从dicts创建项目: 147 | 148 | ```py 149 | >>> Product({'name': 'Laptop PC', 'price': 1500}) 150 | Product(price=1500, name='Laptop PC') 151 | 152 | >>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict 153 | Traceback (most recent call last): 154 | ... 155 | KeyError: 'Product does not support field: lala' 156 | 157 | ``` 158 | 159 | ## 扩展项目 160 | 161 | 您可以通过声明原始项的子类来扩展项(添加更多字段或更改某些字段的元数据)。 162 | 163 | 例如:: 164 | 165 | ```py 166 | class DiscountedProduct(Product): 167 | discount_percent = scrapy.Field(serializer=str) 168 | discount_expiration_date = scrapy.Field() 169 | 170 | ``` 171 | 172 | 您还可以通过使用前面的字段元数据并附加更多值或更改现有值来扩展字段元数据,如: 173 | 174 | ```py 175 | class SpecificProduct(Product): 176 | name = scrapy.Field(Product.fields['name'], serializer=my_serializer) 177 | 178 | ``` 179 | 180 | 添加(或替换)了 `serializer` 的元数据键 `name` 字段,保留所有以前存在的元数据值。 181 | 182 | ## 项目对象 183 | 184 | ```py 185 | class scrapy.item.Item([arg]) 186 | ``` 187 | 188 | 返回从给定参数中可选初始化的新项。 189 | 190 | 项目复制标准 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) 包括其构造函数。项提供的唯一附加属性是: 191 | 192 | ```py 193 | fields 194 | ``` 195 | 196 | 包含 _all declared fields_ 对于这个项目,不仅仅是那些填充的。键是字段名,值是 [`Field`](#scrapy.item.Field "scrapy.item.Field") 中使用的对象 [Item declaration](#topics-items-declaring) . 197 | 198 | ## 字段对象 199 | 200 | ```py 201 | class scrapy.item.Field([arg]) 202 | ``` 203 | 204 | 这个 [`Field`](#scrapy.item.Field "scrapy.item.Field") 类只是内置的别名 [dict](https://docs.python.org/2/library/stdtypes.html#dict) class and doesn't provide any extra functionality or attributes. In other words, [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象是普通的旧python dict。单独的类用于支持 [item declaration syntax](#topics-items-declaring) 基于类属性。 -------------------------------------------------------------------------------- /docs/13.md: -------------------------------------------------------------------------------- 1 | # Scrapy shell 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | scrappyshell是一个交互式shell,您可以在其中快速调试 scrape 代码,而不必运行spider。它本来是用来测试数据提取代码的,但实际上您可以使用它来测试任何类型的代码,因为它也是一个常规的PythonShell。 6 | 7 | shell用于测试xpath或css表达式,并查看它们是如何工作的,以及它们从您试图抓取的网页中提取的数据。它允许您在编写spider时交互地测试表达式,而不必运行spider来测试每个更改。 8 | 9 | 一旦你熟悉了 Scrapy Shell,你就会发现它是开发和调试 Spider 的宝贵工具。 10 | 11 | ## 配置shell 12 | 13 | 如果你有 [IPython](https://ipython.org/) 安装后,scrapy shell将使用它(而不是标准的python控制台)。这个 [IPython](https://ipython.org/) 控制台功能更强大,提供智能自动完成和彩色输出等功能。 14 | 15 | 我们强烈建议您安装 [IPython](https://ipython.org/) ,特别是在使用Unix系统时(其中 [IPython](https://ipython.org/) 擅长)。见 [IPython installation guide](https://ipython.org/install.html) 更多信息。 16 | 17 | Scrapy还支持 [bpython](https://www.bpython-interpreter.org/) ,并将尝试在 [IPython](https://ipython.org/) 不可用。 18 | 19 | 通过Scrapy的设置,您可以将其配置为使用 `ipython` , `bpython` 或标准 `python` Shell,无论安装了什么。这是通过设置 `SCRAPY_PYTHON_SHELL` 环境变量;或通过在 [scrapy.cfg](commands.html#topics-config-settings) :: 20 | 21 | ```py 22 | [settings] 23 | shell = bpython 24 | 25 | ``` 26 | 27 | ## 启动Shell 28 | 29 | 要启动 Scrapy shell,可以使用 [`shell`](commands.html#std:command-shell) 命令如下: 30 | 31 | ```py 32 | scrapy shell 33 | 34 | ``` 35 | 36 | 何处 `<url>` 是要抓取的URL。 37 | 38 | [`shell`](commands.html#std:command-shell) 也适用于本地文件。如果你想玩一个网页的本地副本,这很方便。 [`shell`](commands.html#std:command-shell) 了解本地文件的以下语法:: 39 | 40 | ```py 41 | # UNIX-style 42 | scrapy shell ./path/to/file.html 43 | scrapy shell ../other/path/to/file.html 44 | scrapy shell /absolute/path/to/file.html 45 | 46 | # File URI 47 | scrapy shell file:///absolute/path/to/file.html 48 | 49 | ``` 50 | 51 | 注解 52 | 53 | 使用相对文件路径时,请显式并用 `./` (或) `../` 相关时)。 `scrapy shell index.html` 不会像人们预期的那样工作(这是设计上的,而不是错误)。 54 | 55 | 因为 [`shell`](commands.html#std:command-shell) 喜欢HTTP URL而不是文件URI,以及 `index.html` 在句法上类似于 `example.com` , [`shell`](commands.html#std:command-shell) 会治疗 `index.html` 作为域名并触发DNS查找错误:: 56 | 57 | ```py 58 | $ scrapy shell index.html 59 | [ ... scrapy shell starts ... ] 60 | [ ... traceback ... ] 61 | twisted.internet.error.DNSLookupError: DNS lookup failed: 62 | address 'index.html' not found: [Errno -5] No address associated with hostname. 63 | 64 | ``` 65 | 66 | [`shell`](commands.html#std:command-shell) 如果文件调用了 `index.html` 存在于当前目录中。同样,要明确。 67 | 68 | ## 使用Shell 69 | 70 | scrappyshell只是一个普通的python控制台(或者 [IPython](https://ipython.org/) 控制台,如果你有它的话),它提供一些额外的快捷功能,以方便。 71 | 72 | ### 可用快捷方式 73 | 74 | > * `shelp()` -打印有关可用对象和快捷方式列表的帮助 75 | > * `fetch(url[, redirect=True])` - fetch a new response from the given URL and update all related objects accordingly. You can optionaly ask for HTTP 3xx redirections to not be followed by passing `redirect=False` 76 | > * `fetch(request)` -从给定的请求中获取新的响应,并相应地更新所有相关对象。 77 | > * `view(response)` -在本地Web浏览器中打开给定的响应以进行检查。这将增加一个 [<base> tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) 到响应主体,以便外部链接(如图像和样式表)正确显示。但是请注意,这将在您的计算机中创建一个临时文件,该文件不会自动删除。 78 | 79 | ### 可用的 Scrapy 对象 80 | 81 | Scrapy Shell自动从下载的页面创建一些方便的对象,例如 [`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 对象与 [`Selector`](selectors.html#scrapy.selector.Selector "scrapy.selector.Selector") 对象(用于HTML和XML内容)。 82 | 83 | 这些对象是: 84 | 85 | > * `crawler` -电流 [`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") 对象。 86 | > * `spider` -已知用于处理URL的 Spider ,或 [`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") 如果没有为当前URL找到spider,则为。 87 | > * `request` -A [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 上次提取的页的对象。您可以使用修改此请求 [`replace()`](request-response.html#scrapy.http.Request.replace "scrapy.http.Request.replace") 或者使用 `fetch` 捷径。 88 | > * `response` -A [`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 包含上次提取的页的对象 89 | > * `settings` - the current [Scrapy settings](settings.html#topics-settings) 90 | 91 | ## Shell会话示例 92 | 93 | 下面是一个典型的shell会话的例子,我们从抓取https://scrappy.org页面开始,然后继续抓取https://reddit.com页面。最后,我们修改(reddit)请求方法来发布和重新获取它,得到一个错误。我们通过在Windows中键入ctrl-d(在UNIX系统中)或ctrl-z来结束会话。 94 | 95 | 请记住,在这里提取的数据在您尝试时可能不相同,因为这些页面不是静态的,在您测试时可能已经更改了。这个例子的唯一目的是让您熟悉下脚料Shell的工作原理。 96 | 97 | 首先,我们发射炮弹: 98 | 99 | ```py 100 | scrapy shell 'https://scrapy.org' --nolog 101 | 102 | ``` 103 | 104 | 然后,shell获取URL(使用scrapy下载器)并打印可用对象和有用快捷方式的列表(您会注意到这些行都以 `[s]` 前缀): 105 | 106 | ```py 107 | [s] Available Scrapy objects: 108 | [s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc) 109 | [s] crawler 110 | [s] item {} 111 | [s] request 112 | [s] response <200 https://scrapy.org/> 113 | [s] settings 114 | [s] spider 115 | [s] Useful shortcuts: 116 | [s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed) 117 | [s] fetch(req) Fetch a scrapy.Request and update local objects 118 | [s] shelp() Shell help (print this help) 119 | [s] view(response) View response in a browser 120 | 121 | >>> 122 | 123 | ``` 124 | 125 | 之后,我们可以开始玩对象: 126 | 127 | ```py 128 | >>> response.xpath('//title/text()').get() 129 | 'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework' 130 | 131 | >>> fetch("https://reddit.com") 132 | 133 | >>> response.xpath('//title/text()').get() 134 | 'reddit: the front page of the internet' 135 | 136 | >>> request = request.replace(method="POST") 137 | 138 | >>> fetch(request) 139 | 140 | >>> response.status 141 | 404 142 | 143 | >>> from pprint import pprint 144 | 145 | >>> pprint(response.headers) 146 | {'Accept-Ranges': ['bytes'], 147 | 'Cache-Control': ['max-age=0, must-revalidate'], 148 | 'Content-Type': ['text/html; charset=UTF-8'], 149 | 'Date': ['Thu, 08 Dec 2016 16:21:19 GMT'], 150 | 'Server': ['snooserv'], 151 | 'Set-Cookie': ['loid=KqNLou0V9SKMX4qb4n; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure', 152 | 'loidcreated=2016-12-08T16%3A21%3A19.445Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure', 153 | 'loid=vi0ZVe4NkxNWdlH7r7; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure', 154 | 'loidcreated=2016-12-08T16%3A21%3A19.459Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure'], 155 | 'Vary': ['accept-encoding'], 156 | 'Via': ['1.1 varnish'], 157 | 'X-Cache': ['MISS'], 158 | 'X-Cache-Hits': ['0'], 159 | 'X-Content-Type-Options': ['nosniff'], 160 | 'X-Frame-Options': ['SAMEORIGIN'], 161 | 'X-Moose': ['majestic'], 162 | 'X-Served-By': ['cache-cdg8730-CDG'], 163 | 'X-Timer': ['S1481214079.394283,VS0,VE159'], 164 | 'X-Ua-Compatible': ['IE=edge'], 165 | 'X-Xss-Protection': ['1; mode=block']} 166 | >>> 167 | 168 | ``` 169 | 170 | ## 从spiders调用shell来检查响应 171 | 172 | 有时,您希望检查在您的 Spider 的某个点上正在处理的响应,如果只是检查您期望的响应是否到达那里的话。 173 | 174 | 这可以通过使用 `scrapy.shell.inspect_response` 功能。 175 | 176 | 下面是一个例子,说明如何从您的 Spider 中命名它: 177 | 178 | ```py 179 | import scrapy 180 | 181 | class MySpider(scrapy.Spider): 182 | name = "myspider" 183 | start_urls = [ 184 | "http://example.com", 185 | "http://example.org", 186 | "http://example.net", 187 | ] 188 | 189 | def parse(self, response): 190 | # We want to inspect one specific response. 191 | if ".org" in response.url: 192 | from scrapy.shell import inspect_response 193 | inspect_response(response, self) 194 | 195 | # Rest of parsing code. 196 | 197 | ``` 198 | 199 | 当你运行 Spider 时,你会得到类似的东西: 200 | 201 | ```py 202 | 2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 203 | 2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 204 | [s] Available Scrapy objects: 205 | [s] crawler 206 | ... 207 | 208 | >>> response.url 209 | 'http://example.org' 210 | 211 | ``` 212 | 213 | 然后,您可以检查提取代码是否工作: 214 | 215 | ```py 216 | >>> response.xpath('//h1[@class="fn"]') 217 | [] 218 | 219 | ``` 220 | 221 | 不,不是这样的。所以您可以在Web浏览器中打开响应,看看它是否是您期望的响应: 222 | 223 | ```py 224 | >>> view(response) 225 | True 226 | 227 | ``` 228 | 229 | 最后,单击ctrl-d(或在Windows中单击ctrl-z)退出shell并继续爬网: 230 | 231 | ```py 232 | >>> ^D 233 | 2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 234 | ... 235 | 236 | ``` 237 | 238 | 请注意,您不能使用 `fetch` 这里的快捷方式,因为 Scrapy 的引擎被Shell挡住了。然而,当你离开Shell后, Spider 会继续在它停止的地方爬行,如上图所示。 -------------------------------------------------------------------------------- /docs/14.md: -------------------------------------------------------------------------------- 1 | # 项目管道 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 在一个项目被 Spider 抓取之后,它被发送到项目管道,该管道通过几个按顺序执行的组件来处理它。 6 | 7 | 每个项管道组件(有时称为“项管道”)都是一个实现简单方法的Python类。它们接收一个项目并对其执行操作,还决定该项目是否应继续通过管道,或者是否应删除并不再处理。 8 | 9 | 项目管道的典型用途有: 10 | 11 | * 清理HTML数据 12 | * 验证抓取的数据(检查项目是否包含某些字段) 13 | * 检查重复项(并删除它们) 14 | * 将刮下的项目存储在数据库中 15 | 16 | ## 编写自己的项目管道 17 | 18 | 每个item pipeline组件都是一个python类,必须实现以下方法: 19 | 20 | ```py 21 | process_item(self, item, spider) 22 | ``` 23 | 24 | 对每个项管道组件调用此方法。 [`process_item()`](#process_item "process_item") 必须:返回包含数据的dict,返回 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") (或任何后代类)对象,返回 [Twisted Deferred](https://twistedmatrix.com/documents/current/core/howto/defer.html) or raise [`DropItem`](exceptions.html#scrapy.exceptions.DropItem "scrapy.exceptions.DropItem") 例外。删除的项不再由其他管道组件处理。 25 | 26 | | 参数: | 27 | 28 | * **item** ([`Item`](items.html#scrapy.item.Item "scrapy.item.Item") object or a dict) -- 物品被刮掉了 29 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 刮掉物品的 Spider 30 | 31 | | 32 | | --- | --- | 33 | 34 | 此外,它们还可以实现以下方法: 35 | 36 | ```py 37 | open_spider(self, spider) 38 | ``` 39 | 40 | 当spider打开时调用此方法。 41 | 42 | | 参数: | **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 打开的 Spider | 43 | | --- | --- | 44 | 45 | ```py 46 | close_spider(self, spider) 47 | ``` 48 | 49 | 当spider关闭时调用此方法。 50 | 51 | | 参数: | **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 关闭的 Spider | 52 | | --- | --- | 53 | 54 | ```py 55 | from_crawler(cls, crawler) 56 | ``` 57 | 58 | 如果存在,则调用此ClassMethod从 [`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") . 它必须返回管道的新实例。爬虫对象提供对所有零碎核心组件(如设置和信号)的访问;它是管道访问它们并将其功能连接到零碎的一种方式。 59 | 60 | | 参数: | **crawler** ([`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") object) -- 使用此管道的爬虫程序 | 61 | | --- | --- | 62 | 63 | ## 项目管道示例 64 | 65 | ### 无价格的价格验证和删除项目 66 | 67 | 让我们看看下面的假设管道,它调整了 `price` 不包括增值税的项目的属性( `price_excludes_vat` 属性),并删除不包含价格的项目: 68 | 69 | ```py 70 | from scrapy.exceptions import DropItem 71 | 72 | class PricePipeline(object): 73 | 74 | vat_factor = 1.15 75 | 76 | def process_item(self, item, spider): 77 | if item.get('price'): 78 | if item.get('price_excludes_vat'): 79 | item['price'] = item['price'] * self.vat_factor 80 | return item 81 | else: 82 | raise DropItem("Missing price in %s" % item) 83 | 84 | ``` 85 | 86 | ### 将项目写入JSON文件 87 | 88 | 下面的管道将所有刮掉的项目(从所有 Spider )存储到一个单独的管道中 `items.jl` 文件,每行包含一个以JSON格式序列化的项: 89 | 90 | ```py 91 | import json 92 | 93 | class JsonWriterPipeline(object): 94 | 95 | def open_spider(self, spider): 96 | self.file = open('items.jl', 'w') 97 | 98 | def close_spider(self, spider): 99 | self.file.close() 100 | 101 | def process_item(self, item, spider): 102 | line = json.dumps(dict(item)) + "\n" 103 | self.file.write(line) 104 | return item 105 | 106 | ``` 107 | 108 | 注解 109 | 110 | jsonWriterPipeline的目的只是介绍如何编写项管道。如果您真的想将所有的抓取项存储到JSON文件中,那么应该使用 [Feed exports](feed-exports.html#topics-feed-exports) . 111 | 112 | ### 将项目写入MongoDB 113 | 114 | 在本例中,我们将使用pymongo_uu将项目写入mongodb_u。在Scrapy设置中指定MongoDB地址和数据库名称;MongoDB集合以item类命名。 115 | 116 | 这个例子的要点是演示如何使用 [`from_crawler()`](#from_crawler "from_crawler") 方法和如何正确清理资源。:: 117 | 118 | ```py 119 | import pymongo 120 | 121 | class MongoPipeline(object): 122 | 123 | collection_name = 'scrapy_items' 124 | 125 | def __init__(self, mongo_uri, mongo_db): 126 | self.mongo_uri = mongo_uri 127 | self.mongo_db = mongo_db 128 | 129 | @classmethod 130 | def from_crawler(cls, crawler): 131 | return cls( 132 | mongo_uri=crawler.settings.get('MONGO_URI'), 133 | mongo_db=crawler.settings.get('MONGO_DATABASE', 'items') 134 | ) 135 | 136 | def open_spider(self, spider): 137 | self.client = pymongo.MongoClient(self.mongo_uri) 138 | self.db = self.client[self.mongo_db] 139 | 140 | def close_spider(self, spider): 141 | self.client.close() 142 | 143 | def process_item(self, item, spider): 144 | self.db[self.collection_name].insert_one(dict(item)) 145 | return item 146 | 147 | ``` 148 | 149 | ### 项目截图 150 | 151 | 这个例子演示了如何返回延迟的 [`process_item()`](#process_item "process_item") 方法。它使用splash_u呈现项目url的屏幕截图。管道向本地运行的splash_uuu实例发出请求。在下载请求并触发延迟回调之后,它将项目保存到文件中,并将文件名添加到项目中。 152 | 153 | ```py 154 | import scrapy 155 | import hashlib 156 | from urllib.parse import quote 157 | 158 | class ScreenshotPipeline(object): 159 | """Pipeline that uses Splash to render screenshot of 160 | every Scrapy item.""" 161 | 162 | SPLASH_URL = "http://localhost:8050/render.png?url={}" 163 | 164 | def process_item(self, item, spider): 165 | encoded_item_url = quote(item["url"]) 166 | screenshot_url = self.SPLASH_URL.format(encoded_item_url) 167 | request = scrapy.Request(screenshot_url) 168 | dfd = spider.crawler.engine.download(request, spider) 169 | dfd.addBoth(self.return_item, item) 170 | return dfd 171 | 172 | def return_item(self, response, item): 173 | if response.status != 200: 174 | # Error happened, return item. 175 | return item 176 | 177 | # Save screenshot to file, filename will be hash of url. 178 | url = item["url"] 179 | url_hash = hashlib.md5(url.encode("utf8")).hexdigest() 180 | filename = "{}.png".format(url_hash) 181 | with open(filename, "wb") as f: 182 | f.write(response.body) 183 | 184 | # Store filename in item. 185 | item["screenshot_filename"] = filename 186 | return item 187 | 188 | ``` 189 | 190 | ### 重复筛选器 191 | 192 | 查找重复项并删除已处理的项的筛选器。假设我们的项目有一个唯一的ID,但是我们的spider返回具有相同ID的多个项目: 193 | 194 | ```py 195 | from scrapy.exceptions import DropItem 196 | 197 | class DuplicatesPipeline(object): 198 | 199 | def __init__(self): 200 | self.ids_seen = set() 201 | 202 | def process_item(self, item, spider): 203 | if item['id'] in self.ids_seen: 204 | raise DropItem("Duplicate item found: %s" % item) 205 | else: 206 | self.ids_seen.add(item['id']) 207 | return item 208 | 209 | ``` 210 | 211 | ## 激活项目管道组件 212 | 213 | 若要激活项管道组件,必须将其类添加到 [`ITEM_PIPELINES`](settings.html#std:setting-ITEM_PIPELINES) 设置,如以下示例中所示: 214 | 215 | ```py 216 | ITEM_PIPELINES = { 217 | 'myproject.pipelines.PricePipeline': 300, 218 | 'myproject.pipelines.JsonWriterPipeline': 800, 219 | } 220 | 221 | ``` 222 | 223 | 在此设置中分配给类的整数值决定了它们的运行顺序:项从低值类传递到高值类。习惯上把这些数字定义在0-1000范围内。 -------------------------------------------------------------------------------- /docs/15.md: -------------------------------------------------------------------------------- 1 | # Feed 导出 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 0.10 新版功能. 6 | 7 | 在实现scraper时,最经常需要的功能之一是能够正确地存储被抓取的数据,这通常意味着用被抓取的数据(通常称为“导出提要”)生成一个“导出文件”,供其他系统使用。 8 | 9 | Scrapy随提要导出一起提供了开箱即用的功能,它允许您使用多个序列化格式和存储后端生成带有已擦除项的提要。 10 | 11 | ## 序列化格式 12 | 13 | 为了序列化抓取的数据,提要导出使用 [Item exporters](exporters.html#topics-exporters) . 开箱即用支持这些格式: 14 | 15 | > * [JSON](#topics-feed-format-json) 16 | > * [杰森线](#topics-feed-format-jsonlines) 17 | > * [CSV](#topics-feed-format-csv) 18 | > * [XML](#topics-feed-format-xml) 19 | 20 | 但是您也可以通过 [`FEED_EXPORTERS`](#std:setting-FEED_EXPORTERS) 设置。 21 | 22 | ### JSON 23 | 24 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `json` 25 | > * 出口商: [`JsonItemExporter`](exporters.html#scrapy.exporters.JsonItemExporter "scrapy.exporters.JsonItemExporter") 26 | > * 见 [this warning](exporters.html#json-with-large-data) 如果您使用的是大型提要的JSON。 27 | 28 | ### 杰森线 29 | 30 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `jsonlines` 31 | > * 出口商: [`JsonLinesItemExporter`](exporters.html#scrapy.exporters.JsonLinesItemExporter "scrapy.exporters.JsonLinesItemExporter") 32 | 33 | ### CSV 34 | 35 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `csv` 36 | > * 出口商: [`CsvItemExporter`](exporters.html#scrapy.exporters.CsvItemExporter "scrapy.exporters.CsvItemExporter") 37 | > * 指定要导出的列及其顺序的步骤使用 [`FEED_EXPORT_FIELDS`](#std:setting-FEED_EXPORT_FIELDS) . 其他feed导出器也可以使用此选项,但对于csv很重要,因为与许多其他导出格式不同,csv使用固定头。 38 | 39 | ### XML 40 | 41 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `xml` 42 | > * 出口商: [`XmlItemExporter`](exporters.html#scrapy.exporters.XmlItemExporter "scrapy.exporters.XmlItemExporter") 43 | 44 | ### 泡菜 45 | 46 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `pickle` 47 | > * 出口商: [`PickleItemExporter`](exporters.html#scrapy.exporters.PickleItemExporter "scrapy.exporters.PickleItemExporter") 48 | 49 | ### 元帅 50 | 51 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT): `marshal` 52 | > * 出口商: `MarshalItemExporter` 53 | 54 | ## 储藏室 55 | 56 | 当使用feed导出时,您定义使用uri(通过 [`FEED_URI`](#std:setting-FEED_URI) 设置)。提要导出支持由URI方案定义的多个存储后端类型。 57 | 58 | 开箱支持的存储后端包括: 59 | 60 | > * [本地文件系统](#topics-feed-storage-fs) 61 | > * [FTP](#topics-feed-storage-ftp) 62 | > * [S3](#topics-feed-storage-s3) (需要botocore_u或boto_u) 63 | > * [标准输出](#topics-feed-storage-stdout) 64 | 65 | 如果所需的外部库不可用,则某些存储后端可能不可用。例如,只有在安装了botocore_u或boto_u库的情况下,S3后端才可用(scrapy仅在python 2上支持boto_u)。 66 | 67 | ## 存储URI参数 68 | 69 | 存储URI还可以包含在创建源时被替换的参数。这些参数是: 70 | 71 | > * `%(time)s` -在创建源时被时间戳替换 72 | > * `%(name)s` -替换为 Spider 名称 73 | 74 | 任何其他命名参数都将被同名的spider属性替换。例如, `%(site_id)s` 将被替换为 `spider.site_id` 属性为正在创建源的时刻。 75 | 76 | 下面举例说明: 77 | 78 | > * 使用每个spider一个目录存储在ftp中: 79 | > * `ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json` 80 | > * 使用每个spider一个目录存储在S3中: 81 | > * `s3://mybucket/scraping/feeds/%(name)s/%(time)s.json` 82 | 83 | ## 存储后端 84 | 85 | ### 本地文件系统 86 | 87 | 源存储在本地文件系统中。 88 | 89 | > * URI方案: `file` 90 | > * 示例性URI: `file:///tmp/export.csv` 91 | > * 所需外部库:无 92 | 93 | 请注意,对于本地文件系统存储(仅限),如果您指定类似 `/tmp/export.csv` . 不过,这只在UNIX系统上工作。 94 | 95 | ### FTP 96 | 97 | 这些提要存储在FTP服务器中。 98 | 99 | > * URI方案: `ftp` 100 | > * 示例性URI: `ftp://user:pass@ftp.example.com/path/to/export.csv` 101 | > * 所需外部库:无 102 | 103 | ### S3 104 | 105 | 源存储在 [Amazon S3](https://aws.amazon.com/s3/) . 106 | 107 | > * URI方案: `s3` 108 | > * URI示例: 109 | > * `s3://mybucket/path/to/export.csv` 110 | > * `s3://aws_key:aws_secret@mybucket/path/to/export.csv` 111 | > * 所需的外部库: [botocore](https://github.com/boto/botocore) (python 2和python 3)或 [boto](https://github.com/boto/boto) (仅Python 2) 112 | 113 | AWS凭证可以作为用户/密码在URI中传递,也可以通过以下设置传递: 114 | 115 | > * [`AWS_ACCESS_KEY_ID`](settings.html#std:setting-AWS_ACCESS_KEY_ID) 116 | > * [`AWS_SECRET_ACCESS_KEY`](settings.html#std:setting-AWS_SECRET_ACCESS_KEY) 117 | 118 | 还可以使用此设置为导出的源定义自定义ACL: 119 | 120 | > * [`FEED_STORAGE_S3_ACL`](#std:setting-FEED_STORAGE_S3_ACL) 121 | 122 | ### 标准输出 123 | 124 | 进料被写入废料处理的标准输出。 125 | 126 | > * URI方案: `stdout` 127 | > * 示例性URI: `stdout:` 128 | > * 所需外部库:无 129 | 130 | ## 设置 131 | 132 | 以下是用于配置源导出的设置: 133 | 134 | > * [`FEED_URI`](#std:setting-FEED_URI) (强制性) 135 | > * [`FEED_FORMAT`](#std:setting-FEED_FORMAT) 136 | > * [`FEED_STORAGES`](#std:setting-FEED_STORAGES) 137 | > * [`FEED_STORAGE_S3_ACL`](#std:setting-FEED_STORAGE_S3_ACL) 138 | > * [`FEED_EXPORTERS`](#std:setting-FEED_EXPORTERS) 139 | > * [`FEED_STORE_EMPTY`](#std:setting-FEED_STORE_EMPTY) 140 | > * [`FEED_EXPORT_ENCODING`](#std:setting-FEED_EXPORT_ENCODING) 141 | > * [`FEED_EXPORT_FIELDS`](#std:setting-FEED_EXPORT_FIELDS) 142 | > * [`FEED_EXPORT_INDENT`](#std:setting-FEED_EXPORT_INDENT) 143 | 144 | ### FEED_URI 145 | 146 | 违约: `None` 147 | 148 | 导出源的URI。见 [存储后端](#topics-feed-storage-backends) 用于支持的URI方案。 149 | 150 | 启用源导出需要此设置。 151 | 152 | ### FEED_FORMAT 153 | 154 | 要用于源的序列化格式。见 [序列化格式](#topics-feed-format) 对于可能的值。 155 | 156 | ### FEED_EXPORT_ENCODING 157 | 158 | 违约: `None` 159 | 160 | 要用于源的编码。 161 | 162 | 如果未设置或设置为 `None` (默认)它对除JSON输出之外的所有内容都使用UTF-8,JSON输出使用安全的数字编码。( `\uXXXX` 序列)出于历史原因。 163 | 164 | 使用 `utf-8` 如果您也想要为JSON使用UTF-8。 165 | 166 | ### FEED_EXPORT_FIELDS 167 | 168 | 违约: `None` 169 | 170 | 要导出的字段列表,可选。例子: `FEED_EXPORT_FIELDS = ["foo", "bar", "baz"]` . 171 | 172 | 使用feed_export_fields选项定义要导出的字段及其顺序。 173 | 174 | 当feed-export-fields为空或无时(默认),scrappy使用dicts或 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") Spider 正在屈服的亚纲。 175 | 176 | 如果导出器需要一组固定的字段(这是 [CSV](#topics-feed-format-csv) export format)和feed_export_字段为空或无,然后scrapy尝试从导出的数据中推断字段名-当前它使用第一个项目中的字段名。 177 | 178 | ### FEED_EXPORT_INDENT 179 | 180 | 违约: `0` 181 | 182 | 用于在每个级别上缩进输出的空间量。如果 `FEED_EXPORT_INDENT` 是非负整数,则数组元素和对象成员将以该缩进级别进行漂亮打印。缩进量 `0` (默认值)或负数,将把每个项目放到一个新行上。 `None` 选择最紧凑的表示形式。 183 | 184 | 当前仅由执行 [`JsonItemExporter`](exporters.html#scrapy.exporters.JsonItemExporter "scrapy.exporters.JsonItemExporter") 和 [`XmlItemExporter`](exporters.html#scrapy.exporters.XmlItemExporter "scrapy.exporters.XmlItemExporter") ,即当您要导出到 `.json` 或 `.xml` . 185 | 186 | ### FEED_STORE_EMPTY 187 | 188 | 违约: `False` 189 | 190 | 是否导出空源(即没有项目的源)。 191 | 192 | ### FEED_STORAGES 193 | 194 | 违约: `{{}}` 195 | 196 | 包含项目支持的其他提要存储后端的dict。键是URI方案,值是指向存储类的路径。 197 | 198 | ### FEED_STORAGE_S3_ACL 199 | 200 | 违约: `''` (空字符串) 201 | 202 | 包含项目导出到AmazonS3的源的自定义ACL的字符串。 203 | 204 | 有关可用值的完整列表,请访问 [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) 亚马逊S3文档部分。 205 | 206 | ### FEED_STORAGES_BASE 207 | 208 | 违约:: 209 | 210 | ```py 211 | { 212 | '': 'scrapy.extensions.feedexport.FileFeedStorage', 213 | 'file': 'scrapy.extensions.feedexport.FileFeedStorage', 214 | 'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage', 215 | 's3': 'scrapy.extensions.feedexport.S3FeedStorage', 216 | 'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage', 217 | } 218 | 219 | ``` 220 | 221 | 包含由Scrapy支持的内置提要存储后端的dict。您可以通过分配 `None` 到他们的URI方案 [`FEED_STORAGES`](#std:setting-FEED_STORAGES) . 例如,要禁用内置FTP存储后端(不替换),请将其放入 `settings.py` :: 222 | 223 | ```py 224 | FEED_STORAGES = { 225 | 'ftp': None, 226 | } 227 | 228 | ``` 229 | 230 | ### FEED_EXPORTERS 231 | 232 | 违约: `{{}}` 233 | 234 | 包含项目支持的其他导出器的dict。键是序列化格式,值是指向 [Item exporter](exporters.html#topics-exporters) 类。 235 | 236 | ### FEED_EXPORTERS_BASE 237 | 238 | 违约:: 239 | 240 | ```py 241 | { 242 | 'json': 'scrapy.exporters.JsonItemExporter', 243 | 'jsonlines': 'scrapy.exporters.JsonLinesItemExporter', 244 | 'jl': 'scrapy.exporters.JsonLinesItemExporter', 245 | 'csv': 'scrapy.exporters.CsvItemExporter', 246 | 'xml': 'scrapy.exporters.XmlItemExporter', 247 | 'marshal': 'scrapy.exporters.MarshalItemExporter', 248 | 'pickle': 'scrapy.exporters.PickleItemExporter', 249 | } 250 | 251 | ``` 252 | 253 | 包含由Scrapy支持的内置饲料导出器的dict。您可以通过分配 `None` 到其序列化格式 [`FEED_EXPORTERS`](#std:setting-FEED_EXPORTERS) . 例如,要禁用内置的csv导出器(不替换),请将其放入 `settings.py` :: 254 | 255 | ```py 256 | FEED_EXPORTERS = { 257 | 'csv': None, 258 | } 259 | 260 | ``` -------------------------------------------------------------------------------- /docs/17.md: -------------------------------------------------------------------------------- 1 | # 链接提取器 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 链接提取器是对象,其唯一目的是从网页中提取链接( [`scrapy.http.Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 对象),最终将遵循。 6 | 7 | 有 `scrapy.linkextractors.LinkExtractor` 在Scrapy中可用,但是您可以通过实现一个简单的接口来创建自己的自定义链接提取器来满足您的需要。 8 | 9 | 每个链接提取器唯一拥有的公共方法是 `extract_links` ,接收 [`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 对象并返回 `scrapy.link.Link` 物体。链接提取器将被实例化一次及其 `extract_links` 方法多次调用,并使用不同的响应提取要跟踪的链接。 10 | 11 | 链接提取器用于 [`CrawlSpider`](spiders.html#scrapy.spiders.CrawlSpider "scrapy.spiders.CrawlSpider") 类(在scrappy中可用),通过一组规则,但您也可以在spider中使用它,即使您不从 [`CrawlSpider`](spiders.html#scrapy.spiders.CrawlSpider "scrapy.spiders.CrawlSpider") 因为它的目的很简单:提取链接。 12 | 13 | ## 内置链接提取程序参考 14 | 15 | 在 [`scrapy.linkextractors`](#module-scrapy.linkextractors "scrapy.linkextractors: Link extractors classes") 模块。 16 | 17 | 默认的链接提取程序是 `LinkExtractor` ,与 [`LxmlLinkExtractor`](#scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor "scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor") :: 18 | 19 | ```py 20 | from scrapy.linkextractors import LinkExtractor 21 | 22 | ``` 23 | 24 | 以前的Scrapy版本中还有其他的链接提取器类,但现在已经不推荐使用了。 25 | 26 | ### LxmlLinkExtractor 27 | 28 | ```py 29 | class scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True) 30 | ``` 31 | 32 | LXMLlinkextractor是推荐的带有便捷过滤选项的链接提取程序。它是使用LXML的健壮的HTMLParser实现的。 33 | 34 | | 参数: | 35 | 36 | * **allow** (_a regular expression_ _(or_ _list of__)_) -- (绝对)URL必须匹配才能提取的单个正则表达式(或正则表达式列表)。如果没有给定(或为空),它将匹配所有链接。 37 | * **deny** (_a regular expression_ _(or_ _list of__)_) -- (绝对)URL必须匹配的单个正则表达式(或正则表达式列表)才能排除(即不提取)。它优先于 `allow` 参数。如果未给定(或为空),则不会排除任何链接。 38 | * **allow_domains** (_str_ _or_ _list_) -- 包含用于提取链接的域的单个值或字符串列表。 39 | * **deny_domains** (_str_ _or_ _list_) -- 包含域的单个值或字符串列表,这些域不会被视为提取链接的域。 40 | * **deny_extensions** (_list_) -- 包含在提取链接时应忽略的扩展名的单个值或字符串列表。如果没有给出,它将默认为 `IGNORED_EXTENSIONS` 在中定义的列表 [scrapy.linkextractors](https://github.com/scrapy/scrapy/blob/master/scrapy/linkextractors/__init__.py) 包。 41 | * **restrict_xpaths** (_str_ _or_ _list_) -- 是一个xpath(或xpath的列表),它定义响应中应该从中提取链接的区域。如果给定,则只扫描由这些xpath选择的文本中的链接。见下面的例子。 42 | * **restrict_css** (_str_ _or_ _list_) -- 一个CSS选择器(或选择器列表),它定义响应中应该从中提取链接的区域。行为与 `restrict_xpaths` . 43 | * **restrict_text** (_a regular expression_ _(or_ _list of__)_) -- 链接文本必须匹配才能提取的单个正则表达式(或正则表达式列表)。如果没有给定(或为空),它将匹配所有链接。如果给出了一个正则表达式列表,那么如果链接与至少一个匹配,则将提取该链接。 44 | * **tags** (_str_ _or_ _list_) -- 提取链接时要考虑的标记或标记列表。默认为 `('a', 'area')` . 45 | * **attrs** (_list_) -- 在查找要提取的链接时应考虑的属性或属性列表(仅适用于在 `tags` 参数)。默认为 `('href',)` 46 | * **canonicalize** (_boolean_) -- 规范化每个提取的URL(使用w3lib.url.canonicalize_url)。默认为 `False` . 请注意,规范化URL用于重复检查;它可以更改服务器端可见的URL,因此对于使用规范化URL和原始URL的请求,响应可能不同。如果您使用linkextractor跟踪链接,那么保持默认链接更为可靠。 `canonicalize=False` . 47 | * **unique** (_boolean_) -- 是否对提取的链接应用重复筛选。 48 | * **process_value** (_callable_) -- 一种函数,接收从扫描的标记和属性中提取的每个值,并能修改该值并返回一个新值,或返回 `None` 完全忽略链接。如果没有给出, `process_value` 默认为 `lambda x: x` . …highlight::html例如,要从此代码中提取链接,请执行以下操作::<a href=“javascript:gotopage('../other/page.html');return false“>link text.<a>。highlight::python您可以在 `process_value` ::def process_value(value):m=re.search(“[javascript:gotopage](javascript:gotopage)('(.*?)'”,value)如果m:返回m.group(1) 49 | * **strip** (_boolean_) -- 是否从提取的属性中删除空白。根据HTML5标准,必须从 `href` 属性 `<a>` , `<area>` 还有许多其他元素, `src` 属性 `<img>` , `<iframe>` 元素等,因此linkextractor默认情况下会删除空格字符。集合 `strip=False` 关闭它(例如,如果从允许前导/尾随空格的元素或属性中提取URL)。 50 | 51 | | 52 | | --- | --- | -------------------------------------------------------------------------------- /docs/19.md: -------------------------------------------------------------------------------- 1 | # 例外情况 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | ## 内置异常引用 6 | 7 | 下面是scrapy中包含的所有异常及其用法的列表。 8 | 9 | ### DropItem 10 | 11 | ```py 12 | exception scrapy.exceptions.DropItem 13 | ``` 14 | 15 | 必须由项管道阶段引发的异常才能停止处理项。有关详细信息,请参阅 [项目管道](item-pipeline.html#topics-item-pipeline) . 16 | 17 | ### CloseSpider 18 | 19 | ```py 20 | exception scrapy.exceptions.CloseSpider(reason='cancelled') 21 | ``` 22 | 23 | 可以从 Spider 回调中引发此异常以请求关闭/停止 Spider 。支持的参数: 24 | 25 | | 参数: | **reason** (_str_) -- 关闭的原因 | 26 | | --- | --- | 27 | 28 | 例如:: 29 | 30 | ```py 31 | def parse_page(self, response): 32 | if 'Bandwidth exceeded' in response.body: 33 | raise CloseSpider('bandwidth_exceeded') 34 | 35 | ``` 36 | 37 | ### DontCloseSpider 38 | 39 | ```py 40 | exception scrapy.exceptions.DontCloseSpider 41 | ``` 42 | 43 | 此异常可以在 [`spider_idle`](signals.html#std:signal-spider_idle) 防止 Spider 关闭的信号处理程序。 44 | 45 | ### IgnoreRequest 46 | 47 | ```py 48 | exception scrapy.exceptions.IgnoreRequest 49 | ``` 50 | 51 | 调度程序或任何下载器中间件都可以引发此异常,以指示应忽略请求。 52 | 53 | ### NotConfigured 54 | 55 | ```py 56 | exception scrapy.exceptions.NotConfigured 57 | ``` 58 | 59 | 某些组件可能会引发此异常,以指示它们将保持禁用状态。这些组成部分包括: 60 | 61 | > * 扩展 62 | > * 项目管道 63 | > * 下载器中心件 64 | > * Spider 中心件 65 | 66 | 必须在组件的中引发异常 `__init__` 方法。 67 | 68 | ### NotSupported 69 | 70 | ```py 71 | exception scrapy.exceptions.NotSupported 72 | ``` 73 | 74 | 引发此异常以指示不支持的功能。 -------------------------------------------------------------------------------- /docs/2.md: -------------------------------------------------------------------------------- 1 | # 第一步 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/20.md: -------------------------------------------------------------------------------- 1 | # 内置服务 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/21.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 注解 6 | 7 | `scrapy.log` 已经不赞成与函数一起使用,而赞成显式调用Python标准日志记录。继续阅读以了解有关新日志记录系统的更多信息。 8 | 9 | Scrapy 用途 [Python's builtin logging system](https://docs.python.org/3/library/logging.html) 用于事件日志记录。我们将提供一些简单的示例来帮助您入门,但对于更高级的用例,强烈建议您仔细阅读其文档。 10 | 11 | 日志记录是开箱即用的,可以在某种程度上使用中列出的碎片设置进行配置。 [日志记录设置](#topics-logging-settings) . 12 | 13 | Scrapy电话 [`scrapy.utils.log.configure_logging()`](#scrapy.utils.log.configure_logging "scrapy.utils.log.configure_logging") 设置一些合理的默认值并在 [日志记录设置](#topics-logging-settings) 当运行命令时,建议在运行脚本的scrapy时手动调用它,如中所述。 [从脚本中运行Scrapy](practices.html#run-from-script) . 14 | 15 | ## 日志级别 16 | 17 | python的内置日志记录定义了5个不同的级别,以指示给定日志消息的严重性。以下是标准的,按降序排列: 18 | 19 | 1. `logging.CRITICAL` -对于严重错误(严重性最高) 20 | 2. `logging.ERROR` -对于常规错误 21 | 3. `logging.WARNING` -用于警告消息 22 | 4. `logging.INFO` -以获取信息性消息 23 | 5. `logging.DEBUG` -用于调试消息(最低严重性) 24 | 25 | ## 如何记录消息 26 | 27 | 下面是如何使用 `logging.WARNING` 28 | 29 | ```py 30 | import logging 31 | logging.warning("This is a warning") 32 | 33 | ``` 34 | 35 | 在标准的5个级别中,有一个用于发布日志消息的快捷方式,还有一个常规的 `logging.log` 方法,该方法将给定的级别作为参数。如果需要,最后一个示例可以重写为: 36 | 37 | ```py 38 | import logging 39 | logging.log(logging.WARNING, "This is a warning") 40 | 41 | ``` 42 | 43 | 除此之外,您还可以创建不同的“记录器”来封装消息。(例如,常见的做法是为每个模块创建不同的记录器)。这些记录器可以独立配置,并且允许层次结构。 44 | 45 | 前面的示例在后台使用根记录器,它是一个顶级记录器,所有消息都在其中传播(除非另有规定)。使用 `logging` 帮助程序只是显式获取根记录器的快捷方式,因此这也相当于最后一段代码: 46 | 47 | ```py 48 | import logging 49 | logger = logging.getLogger() 50 | logger.warning("This is a warning") 51 | 52 | ``` 53 | 54 | 您可以使用不同的记录器,只需将其名称 `logging.getLogger` 功能: 55 | 56 | ```py 57 | import logging 58 | logger = logging.getLogger('mycustomlogger') 59 | logger.warning("This is a warning") 60 | 61 | ``` 62 | 63 | 最后,通过使用 `__name__` 变量,用当前模块的路径填充: 64 | 65 | ```py 66 | import logging 67 | logger = logging.getLogger(__name__) 68 | logger.warning("This is a warning") 69 | 70 | ``` 71 | 72 | 参见 73 | 74 | ```py 75 | 模块日志记录, 76 | ``` 77 | 78 | 基本日志教程 79 | 80 | ```py 81 | 模块日志记录, 82 | ``` 83 | 84 | 关于伐木工人的进一步文件 85 | 86 | ## 从 Spider 记录 87 | 88 | Scrapy提供了 [`logger`](spiders.html#scrapy.spiders.Spider.logger "scrapy.spiders.Spider.logger") 在每个 Spider 实例中,可以这样访问和使用: 89 | 90 | ```py 91 | import scrapy 92 | 93 | class MySpider(scrapy.Spider): 94 | 95 | name = 'myspider' 96 | start_urls = ['https://scrapinghub.com'] 97 | 98 | def parse(self, response): 99 | self.logger.info('Parse function called on %s', response.url) 100 | 101 | ``` 102 | 103 | 这个记录器是使用 Spider 的名称创建的,但是您可以使用任何您想要的自定义Python记录器。例如:: 104 | 105 | ```py 106 | import logging 107 | import scrapy 108 | 109 | logger = logging.getLogger('mycustomlogger') 110 | 111 | class MySpider(scrapy.Spider): 112 | 113 | name = 'myspider' 114 | start_urls = ['https://scrapinghub.com'] 115 | 116 | def parse(self, response): 117 | logger.info('Parse function called on %s', response.url) 118 | 119 | ``` 120 | 121 | ## 日志记录配置 122 | 123 | 日志记录者自己不管理如何显示通过它们发送的消息。对于此任务,可以将不同的“处理程序”附加到任何记录器实例,它们将这些消息重定向到适当的目标,例如标准输出、文件、电子邮件等。 124 | 125 | 默认情况下,scrappy根据下面的设置为根记录器设置和配置处理程序。 126 | 127 | ### 日志记录设置 128 | 129 | 这些设置可用于配置日志记录: 130 | 131 | * [`LOG_FILE`](settings.html#std:setting-LOG_FILE) 132 | * [`LOG_ENABLED`](settings.html#std:setting-LOG_ENABLED) 133 | * [`LOG_ENCODING`](settings.html#std:setting-LOG_ENCODING) 134 | * [`LOG_LEVEL`](settings.html#std:setting-LOG_LEVEL) 135 | * [`LOG_FORMAT`](settings.html#std:setting-LOG_FORMAT) 136 | * [`LOG_DATEFORMAT`](settings.html#std:setting-LOG_DATEFORMAT) 137 | * [`LOG_STDOUT`](settings.html#std:setting-LOG_STDOUT) 138 | * [`LOG_SHORT_NAMES`](settings.html#std:setting-LOG_SHORT_NAMES) 139 | 140 | 前两个设置定义日志消息的目标。如果 [`LOG_FILE`](settings.html#std:setting-LOG_FILE) 设置后,通过根记录器发送的消息将被重定向到名为 [`LOG_FILE`](settings.html#std:setting-LOG_FILE) 带编码 [`LOG_ENCODING`](settings.html#std:setting-LOG_ENCODING) . 如果未设置 [`LOG_ENABLED`](settings.html#std:setting-LOG_ENABLED) 是 `True` ,将在标准错误上显示日志消息。最后,如果 [`LOG_ENABLED`](settings.html#std:setting-LOG_ENABLED) 是 `False` ,将不会有任何可见的日志输出。 141 | 142 | [`LOG_LEVEL`](settings.html#std:setting-LOG_LEVEL) 确定要显示的最低严重性级别,将筛选出严重性较低的消息。它的范围包括 [日志级别](#topics-logging-levels) . 143 | 144 | [`LOG_FORMAT`](settings.html#std:setting-LOG_FORMAT) 和 [`LOG_DATEFORMAT`](settings.html#std:setting-LOG_DATEFORMAT) 指定用作所有消息布局的格式字符串。这些字符串可以包含中列出的任何占位符 [logging's logrecord attributes docs](https://docs.python.org/2/library/logging.html#logrecord-attributes) 和 [datetime's strftime and strptime directives](https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior) 分别。 145 | 146 | 如果 [`LOG_SHORT_NAMES`](settings.html#std:setting-LOG_SHORT_NAMES) 设置后,日志将不会显示打印日志的 Scrapy 组件。默认情况下,它是未设置的,因此日志包含负责该日志输出的废料组件。 147 | 148 | ### 命令行选项 149 | 150 | 有一些命令行参数可用于所有命令,您可以使用这些参数来覆盖有关日志记录的一些零碎设置。 151 | 152 | * ```py 153 | --logfile FILE 154 | ``` 155 | 156 | 重写 [`LOG_FILE`](settings.html#std:setting-LOG_FILE) 157 | * ```py 158 | --loglevel/-L LEVEL 159 | ``` 160 | 161 | 重写 [`LOG_LEVEL`](settings.html#std:setting-LOG_LEVEL) 162 | * ```py 163 | --nolog 164 | ``` 165 | 166 | 集合 [`LOG_ENABLED`](settings.html#std:setting-LOG_ENABLED) 到 `False` 167 | 168 | 参见 169 | 170 | ```py 171 | 模块 172 | ``` 173 | 174 | 有关可用处理程序的进一步文档 175 | 176 | ### 高级自定义 177 | 178 | 因为scrapy使用stdlib日志记录模块,所以可以使用stdlib日志记录的所有功能自定义日志记录。 179 | 180 | 例如,假设您正在抓取一个返回许多HTTP 404和500响应的网站,并且您希望隐藏像这样的所有消息: 181 | 182 | ```py 183 | 2016-12-16 22:00:06 [scrapy.spidermiddlewares.httperror] INFO: Ignoring 184 | response <500 http://quotes.toscrape.com/page/1-34/>: HTTP status code 185 | is not handled or not allowed 186 | 187 | ``` 188 | 189 | 首先要注意的是一个记录器名称-它在括号中: `[scrapy.spidermiddlewares.httperror]` . 如果你得到公正 `[scrapy]` 然后 [`LOG_SHORT_NAMES`](settings.html#std:setting-LOG_SHORT_NAMES) 可能设置为true;设置为false并重新运行爬网。 190 | 191 | 接下来,我们可以看到消息具有信息级别。为了隐藏它,我们应该为 `scrapy.spidermiddlewares.httperror` 高于信息;信息后的下一级是警告。可以这样做,例如在 Spider 的 `__init__` 方法: 192 | 193 | ```py 194 | import logging 195 | import scrapy 196 | 197 | class MySpider(scrapy.Spider): 198 | # ... 199 | def __init__(self, *args, **kwargs): 200 | logger = logging.getLogger('scrapy.spidermiddlewares.httperror') 201 | logger.setLevel(logging.WARNING) 202 | super().__init__(*args, **kwargs) 203 | 204 | ``` 205 | 206 | 如果您再次运行此 Spider ,则从 `scrapy.spidermiddlewares.httperror` 日志记录器将消失。 207 | 208 | ## scrapy.utils.log模块 209 | 210 | ```py 211 | scrapy.utils.log.configure_logging(settings=None, install_root_handler=True) 212 | ``` 213 | 214 | 初始化Scrapy的日志记录默认值。 215 | 216 | | 参数: | 217 | 218 | * **settings** (dict, [`Settings`](api.html#scrapy.settings.Settings "scrapy.settings.Settings") object or `None`) -- 用于创建和配置根记录器处理程序的设置(默认值:无)。 219 | * **install_root_handler** (_bool_) -- 是否安装根日志记录处理程序(默认值:true) 220 | 221 | | 222 | | --- | --- | 223 | 224 | 此功能可以: 225 | 226 | * 通过python标准日志记录路由警告和扭曲日志记录 227 | * 分别将调试和错误级别分配给残缺和扭曲的记录器 228 | * 如果日志输出设置为真,则将stdout路由到日志 229 | 230 | 什么时候? `install_root_handler` 为true(默认值),此函数还根据给定的设置为根记录器创建处理程序(请参见 [日志记录设置](#topics-logging-settings) )可以使用替代默认选项 `settings` 争论。什么时候? `settings` 为空或无,使用默认值。 231 | 232 | `configure_logging` 在使用scrappy命令时自动调用,但在运行自定义脚本时需要显式调用。在这种情况下,不需要使用它,但建议使用它。 233 | 234 | 如果您计划自己配置处理程序,仍然建议您调用此函数,通过 `install_root_handler=False` . 请记住,在这种情况下,不会默认设置任何日志输出。 235 | 236 | 要开始手动配置日志输出,可以使用 [logging.basicConfig()](https://docs.python.org/2/library/logging.html#logging.basicConfig) 设置基本根处理程序。这是一个关于如何重定向的示例 `INFO` 或更高的文件消息: 237 | 238 | ```py 239 | import logging 240 | from scrapy.utils.log import configure_logging 241 | 242 | configure_logging(install_root_handler=False) 243 | logging.basicConfig( 244 | filename='log.txt', 245 | format='%(levelname)s: %(message)s', 246 | level=logging.INFO 247 | ) 248 | 249 | ``` 250 | 251 | 参照 [从脚本中运行Scrapy](practices.html#run-from-script) 有关使用scrapy的更多详细信息。 -------------------------------------------------------------------------------- /docs/22.md: -------------------------------------------------------------------------------- 1 | # 统计数据集合 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | Scrapy提供了一种方便的工具,可以以键/值的形式收集统计信息,其中值通常是计数器。该工具称为stats collector,可以通过 [`stats`](api.html#scrapy.crawler.Crawler.stats "scrapy.crawler.Crawler.stats") 的属性 [爬虫API](api.html#topics-api-crawler) ,如中的示例所示 [常用统计信息收集器使用](#topics-stats-usecases) 下面部分。 6 | 7 | 但是,stats collector始终可用,因此无论stats集合是否启用,您都可以将其导入模块并使用其API(以增加或设置新的stat键)。如果它被禁用,API仍然可以工作,但它不会收集任何东西。这是为了简化StatsCollector的用法:在spider、scrappy扩展名或从中使用StatsCollector的任何代码中,收集统计信息的代码不应超过一行。 8 | 9 | StatsCollector的另一个特性是,它在启用时非常高效,在禁用时非常高效(几乎不明显)。 10 | 11 | stats收集器为每个打开的spider保留一个stats表,该表在spider打开时自动打开,在spider关闭时关闭。 12 | 13 | ## 常用统计信息收集器使用 14 | 15 | 通过访问Stats Collector [`stats`](api.html#scrapy.crawler.Crawler.stats "scrapy.crawler.Crawler.stats") 属性。以下是访问统计信息的扩展示例: 16 | 17 | ```py 18 | class ExtensionThatAccessStats(object): 19 | 20 | def __init__(self, stats): 21 | self.stats = stats 22 | 23 | @classmethod 24 | def from_crawler(cls, crawler): 25 | return cls(crawler.stats) 26 | 27 | ``` 28 | 29 | 设置统计值: 30 | 31 | ```py 32 | stats.set_value('hostname', socket.gethostname()) 33 | 34 | ``` 35 | 36 | 增量统计值: 37 | 38 | ```py 39 | stats.inc_value('custom_count') 40 | 41 | ``` 42 | 43 | 仅当大于上一个值时设置stat值:: 44 | 45 | ```py 46 | stats.max_value('max_items_scraped', value) 47 | 48 | ``` 49 | 50 | 仅当低于上一个时设置stat值:: 51 | 52 | ```py 53 | stats.min_value('min_free_memory_percent', value) 54 | 55 | ``` 56 | 57 | 获取统计值: 58 | 59 | ```py 60 | >>> stats.get_value('custom_count') 61 | 1 62 | 63 | ``` 64 | 65 | 获取所有统计数据: 66 | 67 | ```py 68 | >>> stats.get_stats() 69 | {'custom_count': 1, 'start_time': datetime.datetime(2009, 7, 14, 21, 47, 28, 977139)} 70 | 71 | ``` 72 | 73 | ## 可用的统计信息收集器 74 | 75 | 除了基本的 `StatsCollector` Scrapy中还有其他可用的统计数据收集器,它们扩展了基本统计数据收集器。您可以通过 [`STATS_CLASS`](settings.html#std:setting-STATS_CLASS) 设置。使用的默认统计信息收集器是 `MemoryStatsCollector` . 76 | 77 | ### MemoryStatsCollector 78 | 79 | ```py 80 | class scrapy.statscollectors.MemoryStatsCollector 81 | ``` 82 | 83 | 一个简单的统计信息收集器,它在关闭后将上次(每个 Spider )抓取运行的统计信息保存在内存中。可以通过 [`spider_stats`](#scrapy.statscollectors.MemoryStatsCollector.spider_stats "scrapy.statscollectors.MemoryStatsCollector.spider_stats") 属性,它是由 Spider 域名键入的dict。 84 | 85 | 这是Scrapy中使用的默认统计信息收集器。 86 | 87 | ```py 88 | spider_stats 89 | ``` 90 | 91 | 包含每个 Spider 最后一次抓取运行的统计信息的dict的dict(由 Spider 名称键控)。 92 | 93 | ### DummyStatsCollector 94 | 95 | ```py 96 | class scrapy.statscollectors.DummyStatsCollector 97 | ``` 98 | 99 | 一个只做非常有效的统计数据收集器(因为它什么也不做)。此统计信息收集器可以通过 [`STATS_CLASS`](settings.html#std:setting-STATS_CLASS) 设置,以禁用统计信息收集以提高性能。但是,与其他零碎的工作负载(如解析页面)相比,统计数据收集的性能损失通常是微乎其微的。 -------------------------------------------------------------------------------- /docs/23.md: -------------------------------------------------------------------------------- 1 | # 发送电子邮件 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 虽然python使通过 [smtplib](https://docs.python.org/2/library/smtplib.html) Slapy类库提供了自己的发送电子邮件的工具,非常容易使用,并且使用 [Twisted non-blocking IO](https://twistedmatrix.com/documents/current/core/howto/defer-intro.html) ,以避免干扰爬虫的非阻塞IO。它还提供了一个简单的用于发送附件的API,并且非常容易配置,其中有一些 [settings](#topics-email-settings) . 6 | 7 | ## 快速实例 8 | 9 | 有两种方法可以实例化邮件发送者。您可以使用标准构造函数来实例化它: 10 | 11 | ```py 12 | from scrapy.mail import MailSender 13 | mailer = MailSender() 14 | 15 | ``` 16 | 17 | 或者您可以通过一个Scrapy设置对象来实例化它,该对象将尊重 [settings](#topics-email-settings) :: 18 | 19 | ```py 20 | mailer = MailSender.from_settings(settings) 21 | 22 | ``` 23 | 24 | 下面是如何使用它发送电子邮件(不带附件):: 25 | 26 | ```py 27 | mailer.send(to=["someone@example.com"], subject="Some subject", body="Some body", cc=["another@example.com"]) 28 | 29 | ``` 30 | 31 | ## MailSender 类引用 32 | 33 | MailSender 是从scrappy发送电子邮件的首选类,因为它使用 [Twisted non-blocking IO](https://twistedmatrix.com/documents/current/core/howto/defer-intro.html) 和框架的其他部分一样。 34 | 35 | ```py 36 | class scrapy.mail.MailSender(smtphost=None, mailfrom=None, smtpuser=None, smtppass=None, smtpport=None) 37 | ``` 38 | 39 | | 参数: | 40 | 41 | * **smtphost** (_str_ _or_ _bytes_) -- 用于发送电子邮件的SMTP主机。如果省略, [`MAIL_HOST`](#std:setting-MAIL_HOST) 将使用设置。 42 | * **mailfrom** (_str_) -- 用于发送电子邮件的地址(在 `From:` 标题)。如果省略, [`MAIL_FROM`](#std:setting-MAIL_FROM) 将使用设置。 43 | * **smtpuser** -- SMTP用户。如果省略, [`MAIL_USER`](#std:setting-MAIL_USER) 将使用设置。如果未提供,则不会执行任何SMTP身份验证。 44 | * **smtppass** (_str_ _or_ _bytes_) -- 用于身份验证的SMTP通行证。 45 | * **smtpport** (_int_) -- 要连接到的SMTP端口 46 | * **smtptls** (_boolean_) -- 使用smtp starttls强制 47 | * **smtpssl** (_boolean_) -- 强制使用安全的SSL连接 48 | 49 | | 50 | | --- | --- | 51 | 52 | ```py 53 | classmethod from_settings(settings) 54 | ``` 55 | 56 | 使用Scrapy设置对象实例化,该对象将 [these Scrapy settings](#topics-email-settings) . 57 | 58 | | 参数: | **settings** ([`scrapy.settings.Settings`](api.html#scrapy.settings.Settings "scrapy.settings.Settings") object) -- 电子邮件收件人 | 59 | | --- | --- | 60 | 61 | ```py 62 | send(to, subject, body, cc=None, attachs=(), mimetype='text/plain', charset=None) 63 | ``` 64 | 65 | 向指定的收件人发送电子邮件。 66 | 67 | | 参数: | 68 | 69 | * **to** (_str_ _or_ _list of str_) -- 电子邮件收件人 70 | * **subject** (_str_) -- 电子邮件的主题 71 | * **cc** (_str_ _or_ _list of str_) -- 给CC的电子邮件 72 | * **body** (_str_) -- 电子邮件主体 73 | * **attachs** (_iterable_) -- 不可数元组 `(attach_name, mimetype, file_object)` 在哪里? `attach_name` 是一个字符串,其名称将显示在电子邮件附件中, `mimetype` 是附件的mimetype,并且 `file_object` 是具有附件内容的可读文件对象 74 | * **mimetype** (_str_) -- 电子邮件的mime类型 75 | * **charset** (_str_) -- 用于电子邮件内容的字符编码 76 | 77 | | 78 | | --- | --- | 79 | 80 | ## 邮件设置 81 | 82 | 这些设置定义 [`MailSender`](#scrapy.mail.MailSender "scrapy.mail.MailSender") 类,并且可以用于在不编写任何代码的情况下在项目中配置电子邮件通知(对于使用 [`MailSender`](#scrapy.mail.MailSender "scrapy.mail.MailSender") ) 83 | 84 | ### MAIL_FROM 85 | 86 | 违约: `'scrapy@localhost'` 87 | 88 | 要使用的发件人电子邮件( `From:` 头)用于发送电子邮件。 89 | 90 | ### MAIL_HOST 91 | 92 | 违约: `'localhost'` 93 | 94 | 用于发送电子邮件的SMTP主机。 95 | 96 | ### MAIL_PORT 97 | 98 | 违约: `25` 99 | 100 | 用于发送电子邮件的SMTP端口。 101 | 102 | ### MAIL_USER 103 | 104 | 违约: `None` 105 | 106 | 用于SMTP身份验证的用户。如果禁用,将不执行任何SMTP身份验证。 107 | 108 | ### MAIL_PASS 109 | 110 | 违约: `None` 111 | 112 | 用于SMTP身份验证的密码,以及 [`MAIL_USER`](#std:setting-MAIL_USER) . 113 | 114 | ### MAIL_TLS 115 | 116 | 违约: `False` 117 | 118 | 使用starttls强制。starttls是一种获取现有不安全连接并使用ssl/tls将其升级为安全连接的方法。 119 | 120 | ### MAIL_SSL 121 | 122 | 违约: `False` 123 | 124 | 使用SSL加密连接强制连接 -------------------------------------------------------------------------------- /docs/24.md: -------------------------------------------------------------------------------- 1 | # 远程登录控制台 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | Scrapy附带一个内置的telnet控制台,用于检查和控制Scrapy运行过程。telnet控制台只是一个运行在scrappy进程内部的常规python shell,因此您可以从中做任何事情。 6 | 7 | telnet控制台是一个 [built-in Scrapy extension](extensions.html#topics-extensions-ref) 它在默认情况下是启用的,但如果需要,您也可以禁用它。有关扩展本身的更多信息,请参阅 [Telnet控制台扩展](extensions.html#topics-extensions-ref-telnetconsole) . 8 | 9 | 警告 10 | 11 | 通过公共网络使用telnet控制台是不安全的,因为telnet不提供任何传输层安全性。拥有用户名/密码验证不会改变这一点。 12 | 13 | 预期用途是本地连接到正在运行的Scrapy Spider(Spider进程和Telnet客户端在同一台计算机上)或通过安全连接(VPN、SSH通道)进行连接。请避免在不安全的连接上使用telnet控制台,或使用 [`TELNETCONSOLE_ENABLED`](settings.html#std:setting-TELNETCONSOLE_ENABLED) 选择权。 14 | 15 | ## 如何访问telnet控制台 16 | 17 | telnet控制台侦听中定义的TCP端口 [`TELNETCONSOLE_PORT`](#std:setting-TELNETCONSOLE_PORT) 设置,默认为 `6023` . 要访问控制台,您需要键入: 18 | 19 | ```py 20 | telnet localhost 6023 21 | Trying localhost... 22 | Connected to localhost. 23 | Escape character is '^]'. 24 | Username: 25 | Password: 26 | >>> 27 | 28 | ``` 29 | 30 | 默认用户名为 `scrapy` 密码是自动生成的。自动生成的密码可以在垃圾日志中看到,如下所示: 31 | 32 | ```py 33 | 2018-10-16 14:35:21 [scrapy.extensions.telnet] INFO: Telnet Password: 16f92501e8a59326 34 | 35 | ``` 36 | 37 | 默认用户名和密码可以被设置覆盖 [`TELNETCONSOLE_USERNAME`](#std:setting-TELNETCONSOLE_USERNAME) 和 [`TELNETCONSOLE_PASSWORD`](#std:setting-TELNETCONSOLE_PASSWORD) . 38 | 39 | 警告 40 | 41 | 用户名和密码仅提供有限的保护,因为telnet不使用安全传输-默认情况下,即使设置了用户名和密码,通信也不会加密。 42 | 43 | 您需要在Windows和大多数Linux发行版中默认安装的telnet程序。 44 | 45 | ## telnet控制台中的可用变量 46 | 47 | telnet控制台就像一个运行在scrappy进程内部的常规python shell,所以您可以从中做任何事情,包括导入新模块等。 48 | 49 | 但是,telnet控制台附带一些为方便起见而定义的默认变量: 50 | 51 | | 捷径 | 描述 | 52 | | --- | --- | 53 | | `crawler` | 残废的爬虫( [`scrapy.crawler.Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") 对象) | 54 | | `engine` | crawler.engine属性 | 55 | | `spider` | 主动 Spider | 56 | | `slot` | 发动机槽 | 57 | | `extensions` | 扩展管理器(crawler.extensions属性) | 58 | | `stats` | stats收集器(crawler.stats属性) | 59 | | `settings` | Scrapy设置对象(crawler.settings属性) | 60 | | `est` | 打印发动机状态报告 | 61 | | `prefs` | 内存调试(请参见 [调试内存泄漏](leaks.html#topics-leaks) ) | 62 | | `p` | 到的快捷方式 [pprint.pprint](https://docs.python.org/library/pprint.html#pprint.pprint) 功能 | 63 | | `hpy` | 内存调试(请参见 [调试内存泄漏](leaks.html#topics-leaks) ) | 64 | 65 | ## telnet控制台使用示例 66 | 67 | 以下是使用telnet控制台可以执行的一些示例任务: 68 | 69 | ### 查看发动机状态 70 | 71 | 你可以使用 `est()` scrapy引擎使用telnet控制台快速显示其状态的方法: 72 | 73 | ```py 74 | telnet localhost 6023 75 | >>> est() 76 | Execution engine status 77 | 78 | time()-engine.start_time : 8.62972998619 79 | engine.has_capacity() : False 80 | len(engine.downloader.active) : 16 81 | engine.scraper.is_idle() : False 82 | engine.spider.name : followall 83 | engine.spider_is_idle(engine.spider) : False 84 | engine.slot.closing : False 85 | len(engine.slot.inprogress) : 16 86 | len(engine.slot.scheduler.dqs or []) : 0 87 | len(engine.slot.scheduler.mqs) : 92 88 | len(engine.scraper.slot.queue) : 0 89 | len(engine.scraper.slot.active) : 0 90 | engine.scraper.slot.active_size : 0 91 | engine.scraper.slot.itemproc_size : 0 92 | engine.scraper.slot.needs_backout() : False 93 | 94 | ``` 95 | 96 | ### 暂停、恢复和停止 Scrapy 发动机 97 | 98 | 暂停: 99 | 100 | ```py 101 | telnet localhost 6023 102 | >>> engine.pause() 103 | >>> 104 | 105 | ``` 106 | 107 | 恢复: 108 | 109 | ```py 110 | telnet localhost 6023 111 | >>> engine.unpause() 112 | >>> 113 | 114 | ``` 115 | 116 | 停止:: 117 | 118 | ```py 119 | telnet localhost 6023 120 | >>> engine.stop() 121 | Connection closed by foreign host. 122 | 123 | ``` 124 | 125 | ## Telnet控制台信号 126 | 127 | ```py 128 | scrapy.extensions.telnet.update_telnet_vars(telnet_vars) 129 | ``` 130 | 131 | 在telnet控制台打开之前发送。您可以连接到这个信号来添加、删除或更新telnet本地命名空间中可用的变量。为此,需要更新 `telnet_vars` 听写你的处理程序。 132 | 133 | | 参数: | **telnet_vars** (_dict_) -- telnet变量的dict | 134 | | --- | --- | 135 | 136 | ## 远程登录设置 137 | 138 | 以下是控制telnet控制台行为的设置: 139 | 140 | ### TELNETCONSOLE_PORT 141 | 142 | 违约: `[6023, 6073]` 143 | 144 | 用于telnet控制台的端口范围。如果设置为 `None` 或 `0` ,使用动态分配的端口。 145 | 146 | ### TELNETCONSOLE_HOST 147 | 148 | 违约: `'127.0.0.1'` 149 | 150 | telnet控制台应该监听的接口 151 | 152 | ### TELNETCONSOLE_USERNAME 153 | 154 | 违约: `'scrapy'` 155 | 156 | 用于telnet控制台的用户名 157 | 158 | ### TELNETCONSOLE_PASSWORD 159 | 160 | 违约: `None` 161 | 162 | telnet控制台使用的密码,默认行为是让它自动生成。 -------------------------------------------------------------------------------- /docs/25.md: -------------------------------------------------------------------------------- 1 | # Web服务 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | WebService已移动到单独的项目中。 6 | 7 | 它位于: 8 | 9 | > [https://github.com/scrapy-plugins/scrapy-jsonrpc](https://github.com/scrapy-plugins/scrapy-jsonrpc) -------------------------------------------------------------------------------- /docs/26.md: -------------------------------------------------------------------------------- 1 | # 解决具体问题 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/27.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | ## Scrapy与BeautifulSoup或LXML相比如何? 6 | 7 | [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/) 和 [lxml](http://lxml.de/) 是用于分析HTML和XML的库。Scrapy是一个应用程序框架,用于编写爬行网站并从中提取数据的网络 Spider 。 8 | 9 | Scrapy提供了一个用于提取数据的内置机制(称为 [selectors](topics/selectors.html#topics-selectors) )但是你可以很容易地使用 [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/) (或) [lxml](http://lxml.de/) )相反,如果你觉得和他们一起工作更舒服的话。毕竟,它们只是解析可以从任何Python代码导入和使用的库。 10 | 11 | 换句话说,比较 [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/) (或) [lxml](http://lxml.de/) )剪贴就像比较 [jinja2](http://jinja.pocoo.org/) 到 [Django](https://www.djangoproject.com/) . 12 | 13 | ## 我可以用 Scrapy 和 BeautifulSoup 吗? 14 | 15 | 是的,你可以。如上所述 [above](#faq-scrapy-bs-cmp) , [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/) 可用于分析Scrapy回调中的HTML响应。你只需要把反应的身体 `BeautifulSoup` 对象并从中提取所需的任何数据。 16 | 17 | 下面是一个使用BeautifulSoupAPI的 Spider 示例, `lxml` 作为HTML解析器: 18 | 19 | ```py 20 | from bs4 import BeautifulSoup 21 | import scrapy 22 | 23 | class ExampleSpider(scrapy.Spider): 24 | name = "example" 25 | allowed_domains = ["example.com"] 26 | start_urls = ( 27 | 'http://www.example.com/', 28 | ) 29 | 30 | def parse(self, response): 31 | # use lxml to get decent HTML parsing speed 32 | soup = BeautifulSoup(response.text, 'lxml') 33 | yield { 34 | "url": response.url, 35 | "title": soup.h1.string 36 | } 37 | 38 | ``` 39 | 40 | 注解 41 | 42 | `BeautifulSoup` 支持多个HTML/XML分析器。见 [BeautifulSoup's official documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#specifying-the-parser-to-use) 哪些是可用的。 43 | 44 | ## Scrapy支持哪些Python版本? 45 | 46 | scrappy在cpython(默认的python实现)和pypy(从pypy 5.9开始)下支持python 2.7和python 3.4+。python 2.6支持从scrapy 0.20开始被丢弃。Scrapy1.1中添加了python 3支持。在Scrapy 1.4中添加了Pypy支持,在Scrapy 1.5中添加了Pypy3支持。 47 | 48 | 注解 49 | 50 | 对于Windows上的python 3支持,建议使用anaconda/miniconda作为 [outlined in the installation guide](intro/install.html#intro-install-windows) . 51 | 52 | ## Scrapy 有没有从 Django“steal”X? 53 | 54 | 可能吧,但我们不喜欢这个词。我们认为django_u是一个伟大的开源项目,也是一个可以效仿的例子,所以我们把它作为scrappy的灵感来源。 55 | 56 | 我们相信,如果某件事已经做得很好,就没有必要再去改造它。这个概念,除了作为开源和自由软件的基础之一,不仅适用于软件,也适用于文档、程序、政策等。因此,我们选择从已经正确解决了这些问题的项目中复制想法,而不是自己解决每个问题,而是关注我们需要解决的实际问题。奥尔维。 57 | 58 | 如果Scrapy能为其他项目提供灵感,我们会感到骄傲。随时从我们这里偷东西! 59 | 60 | ## Scrapy与HTTP代理一起工作吗? 61 | 62 | 对。通过HTTP代理下载器中间件提供对HTTP代理的支持(因为scrapy 0.8)。见 [`HttpProxyMiddleware`](topics/downloader-middleware.html#scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware") . 63 | 64 | ## 如何在不同的页面中抓取具有属性的项目? 65 | 66 | 见 [向回调函数传递附加数据](topics/request-response.html#topics-request-response-ref-request-callback-arguments) . 67 | 68 | ## scrapy崩溃:importError:没有名为win32api的模块 69 | 70 | 您需要安装 [pywin32](https://sourceforge.net/projects/pywin32/) 因为 [this Twisted bug](https://twistedmatrix.com/trac/ticket/3707) . 71 | 72 | ## 如何在 Spider 中模拟用户登录? 73 | 74 | 见 [使用formRequest.from_response()模拟用户登录](topics/request-response.html#topics-request-response-ref-request-userlogin) . 75 | 76 | ## 是宽度优先还是深度优先? 77 | 78 | 默认情况下,Scrapy使用 [LIFO](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 用于存储挂起请求的队列,这基本上意味着它会爬入 [DFO order](https://en.wikipedia.org/wiki/Depth-first_search) . 这种订单在大多数情况下更方便。如果你真的想爬进去 [BFO order](https://en.wikipedia.org/wiki/Breadth-first_search) ,您可以通过设置以下设置来完成此操作: 79 | 80 | ```py 81 | DEPTH_PRIORITY = 1 82 | SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue' 83 | SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue' 84 | 85 | ``` 86 | 87 | ## 我可怜的爬虫有记忆漏洞。我能做什么? 88 | 89 | 见 [调试内存泄漏](topics/leaks.html#topics-leaks) . 90 | 91 | 另外,python还有一个内置的内存泄漏问题,如中所述。 [无泄漏泄漏](topics/leaks.html#topics-leaks-without-leaks) . 92 | 93 | ## 我怎么能让 Scrapy 消耗更少的记忆? 94 | 95 | 请参阅前面的问题。 96 | 97 | ## 我可以在spider中使用基本的HTTP身份验证吗? 98 | 99 | 是的,看到了 [`HttpAuthMiddleware`](topics/downloader-middleware.html#scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware "scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware") . 100 | 101 | ## 为什么Scrapy用英语而不是我的母语下载页面? 102 | 103 | 尝试更改默认值 [Accept-Language](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) request header by overriding the [`DEFAULT_REQUEST_HEADERS`](topics/settings.html#std:setting-DEFAULT_REQUEST_HEADERS) 设置。 104 | 105 | ## 我在哪里可以找到一些零碎项目的例子? 106 | 107 | 见 [实例](intro/examples.html#intro-examples) . 108 | 109 | ## 我可以在不创建项目的情况下运行 Spider 吗? 110 | 111 | 对。你可以使用 [`runspider`](topics/commands.html#std:command-runspider) 命令。例如,如果有一个 Spider 用 `my_spider.py` 您可以用以下方式运行它的文件: 112 | 113 | ```py 114 | scrapy runspider my_spider.py 115 | 116 | ``` 117 | 118 | 见 [`runspider`](topics/commands.html#std:command-runspider) 命令获取更多信息。 119 | 120 | ## 我收到“过滤的异地请求”消息。我怎么修理它们? 121 | 122 | 这些信息(记录 `DEBUG` 级别)不一定意味着有问题,因此您可能不需要修复它们。 123 | 124 | 这些消息由非现场 Spider 中间件抛出,这是一个 Spider 中间件(默认情况下启用),其目的是过滤掉对 Spider 所覆盖域之外的域的请求。 125 | 126 | 有关详细信息,请参阅: [`OffsiteMiddleware`](topics/spider-middleware.html#scrapy.spidermiddlewares.offsite.OffsiteMiddleware "scrapy.spidermiddlewares.offsite.OffsiteMiddleware") . 127 | 128 | ## 在生产中,建议采用什么方式部署 Scrapy 履带? 129 | 130 | 见 [部署 Spider](topics/deploy.html#topics-deploy) . 131 | 132 | ## 我可以使用JSON进行大型出口吗? 133 | 134 | 这取决于你的产出有多大。见 [this warning](topics/exporters.html#json-with-large-data) 在里面 [`JsonItemExporter`](topics/exporters.html#scrapy.exporters.JsonItemExporter "scrapy.exporters.JsonItemExporter") 文档。 135 | 136 | ## 我可以从信号处理程序返回(扭曲)延迟吗? 137 | 138 | 一些信号支持从其处理程序返回延迟,而另一些则不支持。请参见 [内置信号参考](topics/signals.html#topics-signals-ref) 去知道哪些。 139 | 140 | ## 响应状态代码999是什么意思? 141 | 142 | 999是雅虎网站用来限制请求的自定义响应状态代码。尝试使用下载延迟来降低爬行速度 `2` (或更高)在你的 Spider : 143 | 144 | ```py 145 | class MySpider(CrawlSpider): 146 | 147 | name = 'myspider' 148 | 149 | download_delay = 2 150 | 151 | # [ ... rest of the spider code ... ] 152 | 153 | ``` 154 | 155 | 或者通过在项目中设置全局下载延迟 [`DOWNLOAD_DELAY`](topics/settings.html#std:setting-DOWNLOAD_DELAY) 设置。 156 | 157 | ## 我可以调用吗? `pdb.set_trace()` 从我的 Spider 身上调试它们? 158 | 159 | 是的,但是您也可以使用scriby shell,它允许您快速分析(甚至修改)您的spider正在处理的响应,这通常比普通的老版本更有用。 `pdb.set_trace()` . 160 | 161 | 有关详细信息,请参阅 [从spiders调用shell来检查响应](topics/shell.html#topics-shell-inspect-response) . 162 | 163 | ## 最简单的方法是将我的所有抓取项转储到json/csv/xml文件中? 164 | 165 | 要转储到JSON文件,请执行以下操作: 166 | 167 | ```py 168 | scrapy crawl myspider -o items.json 169 | 170 | ``` 171 | 172 | 要转储到csv文件,请执行以下操作: 173 | 174 | ```py 175 | scrapy crawl myspider -o items.csv 176 | 177 | ``` 178 | 179 | 要转储到XML文件,请执行以下操作: 180 | 181 | ```py 182 | scrapy crawl myspider -o items.xml 183 | 184 | ``` 185 | 186 | 有关详细信息,请参阅 [Feed 导出](topics/feed-exports.html#topics-feed-exports) 187 | 188 | ## 这个巨大的秘密是什么? `__VIEWSTATE` 某些形式中使用的参数? 189 | 190 | 这个 `__VIEWSTATE` 参数用于使用ASP.NET/VB.NET生成的网站。有关其工作方式的详细信息,请参见 [this page](http://search.cpan.org/~ecarroll/HTML-TreeBuilderX-ASP_NET-0.09/lib/HTML/TreeBuilderX/ASP_NET.pm) . 还有,这里有一个 [example spider](https://github.com/AmbientLighter/rpn-fas/blob/master/fas/spiders/rnp.py) 会刮伤其中一个站点。 191 | 192 | ## 解析大型XML/CSV数据源的最佳方法是什么? 193 | 194 | 使用xpath选择器解析大型提要可能会有问题,因为它们需要在内存中构建整个提要的DOM,这可能会非常慢,并且会消耗大量内存。 195 | 196 | 为了避免在内存中一次分析所有提要,可以使用函数 `xmliter` 和 `csviter` 从 `scrapy.utils.iterators` 模块。事实上,这就是食性 Spider (参见 [Spider](topics/spiders.html#topics-spiders) )在盖下使用。 197 | 198 | ## Scrapy是否自动管理cookies? 199 | 200 | 是的,Scrapy接收并跟踪服务器发送的cookie,并像任何普通的Web浏览器一样,在随后的请求中发送它们。 201 | 202 | 有关详细信息,请参阅 [请求和响应](topics/request-response.html#topics-request-response) 和 [CookiesMiddleware](topics/downloader-middleware.html#cookies-mw) . 203 | 204 | ## 我如何才能看到从Scrapy发送和接收的cookies? 205 | 206 | 启用 [`COOKIES_DEBUG`](topics/downloader-middleware.html#std:setting-COOKIES_DEBUG) 设置。 207 | 208 | ## 我怎样才能指示 Spider 停止自己呢? 209 | 210 | 提高 [`CloseSpider`](topics/exceptions.html#scrapy.exceptions.CloseSpider "scrapy.exceptions.CloseSpider") 回调异常。有关详细信息,请参阅: [`CloseSpider`](topics/exceptions.html#scrapy.exceptions.CloseSpider "scrapy.exceptions.CloseSpider") . 211 | 212 | ## 我怎样才能防止我的废机器人被禁止? 213 | 214 | 见 [避免被禁止](topics/practices.html#bans) . 215 | 216 | ## 我应该使用 Spider 参数或设置来配置我的 Spider 吗? 217 | 218 | 两个 [spider arguments](topics/spiders.html#spiderargs) 和 [settings](topics/settings.html#topics-settings) 可以用来配置 Spider 。没有strict的规则要求使用其中一个或另一个,但是设置更适合于参数,一旦设置,就不会改变太多,而spider参数的更改更频繁,甚至在每次spider运行时,有时甚至需要spider运行(例如,设置spider的起始URL)。 219 | 220 | 举个例子来说明,假设您有一个 Spider 需要登录到一个站点来获取数据,并且您只想从站点的某个部分(每次都不同)获取数据。在这种情况下,登录的凭证将是设置,而要擦除的部分的URL将是spider参数。 221 | 222 | ## 我正在抓取一个XML文档,而我的xpath选择器没有返回任何项 223 | 224 | 可能需要删除命名空间。见 [正在删除命名空间](topics/selectors.html#removing-namespaces) . -------------------------------------------------------------------------------- /docs/28.md: -------------------------------------------------------------------------------- 1 | # 调试spiders 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 本文档介绍调试spider的最常用技术。考虑下面的残废 Spider : 6 | 7 | ```py 8 | import scrapy 9 | from myproject.items import MyItem 10 | 11 | class MySpider(scrapy.Spider): 12 | name = 'myspider' 13 | start_urls = ( 14 | 'http://example.com/page1', 15 | 'http://example.com/page2', 16 | ) 17 | 18 | def parse(self, response): 19 | # 20 | # collect `item_urls` 21 | for item_url in item_urls: 22 | yield scrapy.Request(item_url, self.parse_item) 23 | 24 | def parse_item(self, response): 25 | # 26 | item = MyItem() 27 | # populate `item` fields 28 | # and extract item_details_url 29 | yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item}) 30 | 31 | def parse_details(self, response): 32 | item = response.meta['item'] 33 | # populate more `item` fields 34 | return item 35 | 36 | ``` 37 | 38 | 基本上,这是一个简单的spider,它解析两页项目(start-url)。项目还有一个包含附加信息的详细信息页,因此我们使用 `meta` 的功能 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 传递部分填充的项。 39 | 40 | ## 解析命令 41 | 42 | 检查 Spider 输出的最基本方法是使用 [`parse`](commands.html#std:command-parse) 命令。它允许在方法级别检查spider的不同部分的行为。它的优点是灵活和易于使用,但不允许在方法内部调试代码。 43 | 44 | 为了查看从特定URL中获取的项目: 45 | 46 | ```py 47 | $ scrapy parse --spider=myspider -c parse_item -d 2 48 | [ ... scrapy log lines crawling example.com spider ... ] 49 | 50 | >>> STATUS DEPTH LEVEL 2 <<< 51 | # Scraped Items ------------------------------------------------------------ 52 | [{'url': }] 53 | 54 | # Requests ----------------------------------------------------------------- 55 | [] 56 | 57 | ``` 58 | 59 | 使用 `--verbose` 或 `-v` 选项我们可以看到每个深度级别的状态: 60 | 61 | ```py 62 | $ scrapy parse --spider=myspider -c parse_item -d 2 -v 63 | [ ... scrapy log lines crawling example.com spider ... ] 64 | 65 | >>> DEPTH LEVEL: 1 <<< 66 | # Scraped Items ------------------------------------------------------------ 67 | [] 68 | 69 | # Requests ----------------------------------------------------------------- 70 | [] 71 | 72 | >>> DEPTH LEVEL: 2 <<< 73 | # Scraped Items ------------------------------------------------------------ 74 | [{'url': }] 75 | 76 | # Requests ----------------------------------------------------------------- 77 | [] 78 | 79 | ``` 80 | 81 | 检查从一个开始的项目,也可以很容易地实现使用:: 82 | 83 | ```py 84 | $ scrapy parse --spider=myspider -d 3 'http://example.com/page1' 85 | 86 | ``` 87 | 88 | ## Scrapy Shell 89 | 90 | 而 [`parse`](commands.html#std:command-parse) 命令对于检查 Spider 的行为非常有用,除了显示接收到的响应和输出之外,检查回调中发生的情况几乎没有帮助。如何调试情况 `parse_details` 有时没有收到物品? 91 | 92 | 幸运的是, [`shell`](commands.html#std:command-shell) 在这种情况下,你的面包和黄油(见 [从spiders调用shell来检查响应](shell.html#topics-shell-inspect-response) ): 93 | 94 | ```py 95 | from scrapy.shell import inspect_response 96 | 97 | def parse_details(self, response): 98 | item = response.meta.get('item', None) 99 | if item: 100 | # populate more `item` fields 101 | return item 102 | else: 103 | inspect_response(response, self) 104 | 105 | ``` 106 | 107 | 参见: [从spiders调用shell来检查响应](shell.html#topics-shell-inspect-response) . 108 | 109 | ## 在浏览器中打开 110 | 111 | 有时,您只想查看某个响应在浏览器中的外观,可以使用 `open_in_browser` 功能。以下是您将如何使用它的示例: 112 | 113 | ```py 114 | from scrapy.utils.response import open_in_browser 115 | 116 | def parse_details(self, response): 117 | if "item name" not in response.body: 118 | open_in_browser(response) 119 | 120 | ``` 121 | 122 | `open_in_browser` 将打开一个浏览器,此时Scrapy接收到响应,调整 [base tag](https://www.w3schools.com/tags/tag_base.asp) 以便正确显示图像和样式。 123 | 124 | ## Logging 125 | 126 | 日志记录是获取 Spider 运行信息的另一个有用选项。尽管不太方便,但它的优点是,如果需要,日志在将来的所有运行中都将可用: 127 | 128 | ```py 129 | def parse_details(self, response): 130 | item = response.meta.get('item', None) 131 | if item: 132 | # populate more `item` fields 133 | return item 134 | else: 135 | self.logger.warning('No item received for %s', response.url) 136 | 137 | ``` 138 | 139 | 有关详细信息,请检查 [Logging](logging.html#topics-logging) 部分。 -------------------------------------------------------------------------------- /docs/29.md: -------------------------------------------------------------------------------- 1 | # Spider 合约 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 0.15 新版功能. 6 | 7 | 注解 8 | 9 | 这是一个新功能(在Scrapy0.15中引入),可能会受到小功能/API更新的影响。检查 [release notes](../news.html#news) 收到更新通知。 10 | 11 | 测试 Spider 会变得特别烦人,虽然没有什么可以阻止你编写单元测试,但是任务会很快变得很麻烦。Scrapy提供了一种综合的方法,可以通过合同的方式测试你的 Spider 。 12 | 13 | 这允许您通过硬编码一个示例URL来测试 Spider 的每个回调,并检查回调如何处理响应的各种约束。每个合同的前缀都是 `@` 并包含在docstring中。请参见以下示例: 14 | 15 | ```py 16 | def parse(self, response): 17 | """ This function parses a sample response. Some contracts are mingled 18 | with this docstring. 19 | 20 | @url http://www.amazon.com/s?field-keywords=selfish+gene 21 | @returns items 1 16 22 | @returns requests 0 0 23 | @scrapes Title Author Year Price 24 | """ 25 | 26 | ``` 27 | 28 | 此回调使用三个内置合同进行测试: 29 | 30 | ```py 31 | class scrapy.contracts.default.UrlContract 32 | ``` 33 | 34 | 本合同(合同) `@url` )设置检查此spider的其他合同条件时使用的示例URL。本合同是强制性的。运行检查时将忽略缺少此协定的所有回调:: 35 | 36 | ```py 37 | @url url 38 | 39 | ``` 40 | 41 | ```py 42 | class scrapy.contracts.default.ReturnsContract 43 | ``` 44 | 45 | 本合同(合同) `@returns` )为 Spider 返回的项和请求设置下限和上限。上限是可选的: 46 | 47 | ```py 48 | @returns item(s)|request(s) [min [max]] 49 | 50 | ``` 51 | 52 | ```py 53 | class scrapy.contracts.default.ScrapesContract 54 | ``` 55 | 56 | 本合同(合同) `@scrapes` )检查回调返回的所有项是否具有指定的字段:: 57 | 58 | ```py 59 | @scrapes field_1 field_2 ... 60 | 61 | ``` 62 | 63 | 使用 [`check`](commands.html#std:command-check) 运行合同检查的命令。 64 | 65 | ## 定制合同 66 | 67 | 如果您发现您需要比内置的零碎合同更多的电力,您可以使用 [`SPIDER_CONTRACTS`](settings.html#std:setting-SPIDER_CONTRACTS) 设置: 68 | 69 | ```py 70 | SPIDER_CONTRACTS = { 71 | 'myproject.contracts.ResponseCheck': 10, 72 | 'myproject.contracts.ItemValidate': 10, 73 | } 74 | 75 | ``` 76 | 77 | 每个合同必须继承自 [`scrapy.contracts.Contract`](#scrapy.contracts.Contract "scrapy.contracts.Contract") 可以覆盖三种方法: 78 | 79 | ```py 80 | class scrapy.contracts.Contract(method, *args) 81 | ``` 82 | 83 | | 参数: | 84 | 85 | * **method** (_function_) -- 与合同关联的回调函数 86 | * **args** (_list_) -- 传入docstring的参数列表(空格分隔) 87 | 88 | | 89 | | --- | --- | 90 | 91 | ```py 92 | adjust_request_args(args) 93 | ``` 94 | 95 | 这接收了 `dict` 作为包含请求对象的默认参数的参数。 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 默认情况下使用,但可以使用 `request_cls` 属性。如果链中的多个合同定义了此属性,则使用最后一个。 96 | 97 | 必须返回相同或修改过的版本。 98 | 99 | ```py 100 | pre_process(response) 101 | ``` 102 | 103 | 这允许在将样本请求传递到回调之前,对从该请求接收的响应进行各种检查。 104 | 105 | ```py 106 | post_process(output) 107 | ``` 108 | 109 | 这允许处理回调的输出。迭代器在传递给这个Hook之前被转换为列表化的。 110 | 111 | 这里是一个演示合同,它检查在收到的响应中是否存在自定义头。提高 `scrapy.exceptions.ContractFail` 为了让故障得到完美的打印: 112 | 113 | ```py 114 | from scrapy.contracts import Contract 115 | from scrapy.exceptions import ContractFail 116 | 117 | class HasHeaderContract(Contract): 118 | """ Demo contract which checks the presence of a custom header 119 | @has_header X-CustomHeader 120 | """ 121 | 122 | name = 'has_header' 123 | 124 | def pre_process(self, response): 125 | for header in self.args: 126 | if header not in response.headers: 127 | raise ContractFail('X-CustomHeader not present') 128 | 129 | ``` -------------------------------------------------------------------------------- /docs/3.md: -------------------------------------------------------------------------------- 1 | # Scrapy at a glance 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | Scrapy是一个应用程序框架,用于对网站进行爬行和提取结构化数据,这些结构化数据可用于各种有用的应用程序,如数据挖掘、信息处理或历史存档。 6 | 7 | 尽管Scrapy最初是为 [web scraping](https://en.wikipedia.org/wiki/Web_scraping) 它还可以用于使用API提取数据(例如 [Amazon Associates Web Services](https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html) )或者作为一个通用的网络爬虫。 8 | 9 | ## 浏览示例 Spider 10 | 11 | 为了向您展示Scrapy给桌子带来了什么,我们将用最简单的方法来运行一个Scrapy Spider 的例子。 12 | 13 | 以下是一个 Spider 代码,它从网站http://quotes.toscrape.com上抓取著名的引语,按照以下页码: 14 | 15 | ```py 16 | import scrapy 17 | 18 | class QuotesSpider(scrapy.Spider): 19 | name = 'quotes' 20 | start_urls = [ 21 | 'http://quotes.toscrape.com/tag/humor/', 22 | ] 23 | 24 | def parse(self, response): 25 | for quote in response.css('div.quote'): 26 | yield { 27 | 'text': quote.css('span.text::text').get(), 28 | 'author': quote.xpath('span/small/text()').get(), 29 | } 30 | 31 | next_page = response.css('li.next a::attr("href")').get() 32 | if next_page is not None: 33 | yield response.follow(next_page, self.parse) 34 | 35 | ``` 36 | 37 | 把它放在一个文本文件中,命名为 `quotes_spider.py` 然后用 [`runspider`](../topics/commands.html#std:command-runspider) 命令: 38 | 39 | ```py 40 | scrapy runspider quotes_spider.py -o quotes.json 41 | 42 | ``` 43 | 44 | 完成后,您将 `quotes.json` 以JSON格式提交一个引号列表,其中包含文本和作者,如下所示(此处重新格式化以提高可读性): 45 | 46 | ```py 47 | [{ 48 | "author": "Jane Austen", 49 | "text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d" 50 | }, 51 | { 52 | "author": "Groucho Marx", 53 | "text": "\u201cOutside of a dog, a book is man's best friend. Inside of a dog it's too dark to read.\u201d" 54 | }, 55 | { 56 | "author": "Steve Martin", 57 | "text": "\u201cA day without sunshine is like, you know, night.\u201d" 58 | }, 59 | ...] 60 | 61 | ``` 62 | 63 | ### 刚刚发生了什么? 64 | 65 | 当你运行命令时 `scrapy runspider quotes_spider.py` 斯克里奇在里面寻找 Spider 的定义,然后用它的爬行引擎运行。 66 | 67 | 通过向中定义的URL发出请求启动的爬网 `start_urls` 属性(在本例中,只有引号的URL _humor_ 并调用默认回调方法 `parse` ,将响应对象作为参数传递。在 `parse` 回调,我们使用CSS选择器循环引用元素,生成一个包含提取的引号文本和作者的python dict,查找到下一页的链接,并使用它调度另一个请求。 `parse` 方法作为回调。 68 | 69 | 在这里,您注意到Scrapy的一个主要优点:请求是 [scheduled and processed asynchronously](../topics/architecture.html#topics-architecture) . 这意味着Scrapy不需要等待请求完成和处理,它可以同时发送另一个请求或做其他事情。这也意味着,即使某些请求失败或在处理过程中发生错误,其他请求也可以继续进行。 70 | 71 | 虽然这使您能够非常快速地进行爬行(同时以容错的方式发送多个并发请求),但Scrapy还使您能够控制爬行的礼貌性。 [a few settings](../topics/settings.html#topics-settings-ref) . 您可以在每个请求之间设置下载延迟、限制每个域或每个IP的并发请求量,甚至 [using an auto-throttling extension](../topics/autothrottle.html#topics-autothrottle) 它试图自动解决这些问题。 72 | 73 | 注解 74 | 75 | 这是使用 [feed exports](../topics/feed-exports.html#topics-feed-exports) 要生成JSON文件,您可以轻松地更改导出格式(例如XML或CSV)或存储后端(FTP或 [Amazon S3](https://aws.amazon.com/s3/) 例如)。你也可以写一个 [item pipeline](../topics/item-pipeline.html#topics-item-pipeline) 将项目存储在数据库中。 76 | 77 | ## 还有什么? 78 | 79 | 你已经看到了如何使用Scrapy从网站中提取和存储项目,但这只是表面现象。Scrapy提供了许多强大的功能,使抓取变得简单和高效,例如: 80 | 81 | * 内置支持 [selecting and extracting](../topics/selectors.html#topics-selectors) 使用扩展的CSS选择器和XPath表达式从HTML/XML源中获取数据,并使用正则表达式提取助手方法。 82 | * 安 [interactive shell console](../topics/shell.html#topics-shell) (ipython-aware)用于尝试使用css和xpath表达式来获取数据,在编写或调试spider时非常有用。 83 | * 内置支持 [generating feed exports](../topics/feed-exports.html#topics-feed-exports) 以多种格式(json、csv、xml)存储在多个后端(ftp、s3、本地文件系统) 84 | * 强大的编码支持和自动检测,用于处理外部、非标准和中断的编码声明。 85 | * [Strong extensibility support](../index.html#extending-scrapy) ,允许您使用 [signals](../topics/signals.html#topics-signals) 以及定义良好的API(中间件, [extensions](../topics/extensions.html#topics-extensions) 和 [pipelines](../topics/item-pipeline.html#topics-item-pipeline) ) 86 | * 广泛的内置扩展和用于处理的中间产品: 87 | * cookie和会话处理 88 | * HTTP功能,如压缩、身份验证、缓存 89 | * 用户代理欺骗 90 | * robots.txt 91 | * 爬行深度限制 92 | * 更多 93 | * A [Telnet console](../topics/telnetconsole.html#topics-telnetconsole) 用于挂接到运行在Scrapy进程中的Python控制台,以便内省和调试爬虫程序 94 | * 还有其他的好东西,比如可重复使用的 Spider [Sitemaps](https://www.sitemaps.org/index.html) 和XML/CSV源,这是 [automatically downloading images](../topics/media-pipeline.html#topics-media-pipeline) (或任何其他媒体)与抓取的项目、缓存DNS解析程序等相关! 95 | 96 | ## 下一步是什么? 97 | 98 | 接下来的步骤是 [install Scrapy](install.html#intro-install) , [follow through the tutorial](tutorial.html#intro-tutorial) 学习如何创建一个完整的 Scrapy 项目和 [join the community](https://scrapy.org/community/) . 感谢您的关注! -------------------------------------------------------------------------------- /docs/30.md: -------------------------------------------------------------------------------- 1 | # 常用做法 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 本节记录使用Scrapy时的常见做法。这些内容涵盖了许多主题,通常不属于任何其他特定部分。 6 | 7 | ## 从脚本中运行Scrapy 8 | 9 | 你可以使用 [API](api.html#topics-api) 从脚本运行scrapy,而不是运行scrapy via的典型方式 `scrapy crawl` . 10 | 11 | 记住,scrappy构建在TwistedAsynchronicNetworkLibrary之上,所以需要在TwistedReactor中运行它。 12 | 13 | 你能用来运行 Spider 的第一个工具是 `scrapy.crawler.CrawlerProcess` . 这个类将为您启动一个扭曲的反应器,配置日志记录和设置关闭处理程序。这个类是所有slapy命令使用的类。 14 | 15 | 下面是一个示例,演示如何使用它运行单个 Spider 。 16 | 17 | ```py 18 | import scrapy 19 | from scrapy.crawler import CrawlerProcess 20 | 21 | class MySpider(scrapy.Spider): 22 | # Your spider definition 23 | ... 24 | 25 | process = CrawlerProcess({ 26 | 'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)' 27 | }) 28 | 29 | process.crawl(MySpider) 30 | process.start() # the script will block here until the crawling is finished 31 | 32 | ``` 33 | 34 | 一定要检查 `CrawlerProcess` 了解其使用细节的文档。 35 | 36 | 如果您在一个零碎的项目中,有一些额外的帮助器可以用来导入项目中的那些组件。你可以自动输入 Spider 的名字 `CrawlerProcess` 及使用 `get_project_settings` 得到一个 [`Settings`](api.html#scrapy.settings.Settings "scrapy.settings.Settings") 具有项目设置的实例。 37 | 38 | 下面是一个如何使用 [testspiders](https://github.com/scrapinghub/testspiders) 以项目为例。 39 | 40 | ```py 41 | from scrapy.crawler import CrawlerProcess 42 | from scrapy.utils.project import get_project_settings 43 | 44 | process = CrawlerProcess(get_project_settings()) 45 | 46 | # 'followall' is the name of one of the spiders of the project. 47 | process.crawl('followall', domain='scrapinghub.com') 48 | process.start() # the script will block here until the crawling is finished 49 | 50 | ``` 51 | 52 | 还有另一个Scrapy实用程序,它提供了对爬行过程的更多控制: `scrapy.crawler.CrawlerRunner` . 这个类是一个薄包装器,它封装了一些简单的帮助器来运行多个爬行器,但是它不会以任何方式启动或干扰现有的反应器。 53 | 54 | 使用这个类,在调度spider之后应该显式地运行reactor。建议您使用 `CrawlerRunner` 而不是 `CrawlerProcess` 如果您的应用程序已经在使用Twisted,并且您希望在同一个反应器中运行Scrapy。 55 | 56 | 请注意, Spider 完成后,您还必须自己关闭扭曲的反应堆。这可以通过将回调添加到由 `CrawlerRunner.crawl` 方法。 57 | 58 | 下面是一个使用它的例子,以及在 `MySpider` 已完成运行。 59 | 60 | ```py 61 | from twisted.internet import reactor 62 | import scrapy 63 | from scrapy.crawler import CrawlerRunner 64 | from scrapy.utils.log import configure_logging 65 | 66 | class MySpider(scrapy.Spider): 67 | # Your spider definition 68 | ... 69 | 70 | configure_logging({'LOG_FORMAT': '%(levelname)s: %(message)s'}) 71 | runner = CrawlerRunner() 72 | 73 | d = runner.crawl(MySpider) 74 | d.addBoth(lambda _: reactor.stop()) 75 | reactor.run() # the script will block here until the crawling is finished 76 | 77 | ``` 78 | 79 | 参见 80 | 81 | [Twisted Reactor Overview](https://twistedmatrix.com/documents/current/core/howto/reactor-basics.html) . 82 | 83 | ## 在同一进程中运行多个spider 84 | 85 | 默认情况下,当您运行时,scrapy为每个进程运行一个spider `scrapy crawl` . 但是,Scrapy支持使用 [internal API](api.html#topics-api) . 86 | 87 | 下面是一个同时运行多个 Spider 的示例: 88 | 89 | ```py 90 | import scrapy 91 | from scrapy.crawler import CrawlerProcess 92 | 93 | class MySpider1(scrapy.Spider): 94 | # Your first spider definition 95 | ... 96 | 97 | class MySpider2(scrapy.Spider): 98 | # Your second spider definition 99 | ... 100 | 101 | process = CrawlerProcess() 102 | process.crawl(MySpider1) 103 | process.crawl(MySpider2) 104 | process.start() # the script will block here until all crawling jobs are finished 105 | 106 | ``` 107 | 108 | 使用相同的示例 `CrawlerRunner` : 109 | 110 | ```py 111 | import scrapy 112 | from twisted.internet import reactor 113 | from scrapy.crawler import CrawlerRunner 114 | from scrapy.utils.log import configure_logging 115 | 116 | class MySpider1(scrapy.Spider): 117 | # Your first spider definition 118 | ... 119 | 120 | class MySpider2(scrapy.Spider): 121 | # Your second spider definition 122 | ... 123 | 124 | configure_logging() 125 | runner = CrawlerRunner() 126 | runner.crawl(MySpider1) 127 | runner.crawl(MySpider2) 128 | d = runner.join() 129 | d.addBoth(lambda _: reactor.stop()) 130 | 131 | reactor.run() # the script will block here until all crawling jobs are finished 132 | 133 | ``` 134 | 135 | 同样的例子,但是通过链接延迟来按顺序运行spider: 136 | 137 | ```py 138 | from twisted.internet import reactor, defer 139 | from scrapy.crawler import CrawlerRunner 140 | from scrapy.utils.log import configure_logging 141 | 142 | class MySpider1(scrapy.Spider): 143 | # Your first spider definition 144 | ... 145 | 146 | class MySpider2(scrapy.Spider): 147 | # Your second spider definition 148 | ... 149 | 150 | configure_logging() 151 | runner = CrawlerRunner() 152 | 153 | @defer.inlineCallbacks 154 | def crawl(): 155 | yield runner.crawl(MySpider1) 156 | yield runner.crawl(MySpider2) 157 | reactor.stop() 158 | 159 | crawl() 160 | reactor.run() # the script will block here until the last crawl call is finished 161 | 162 | ``` 163 | 164 | 参见 165 | 166 | [从脚本中运行Scrapy](#run-from-script) . 167 | 168 | ## 分布式爬行 169 | 170 | Scrapy不提供任何以分布式(多服务器)方式运行爬虫的内置工具。但是,有一些分发爬行的方法,这取决于您计划如何分发爬行。 171 | 172 | 如果您有许多 Spider ,那么分配负载的最明显的方法就是设置许多ScrapyD实例,并将 Spider 运行分布在这些实例中。 173 | 174 | 如果您想在多台机器上运行一个(大) Spider ,通常需要对URL进行分区,以便爬行并将它们发送到每个单独的 Spider 。下面是一个具体的例子: 175 | 176 | 首先,准备要爬网的URL列表并将其放入单独的文件/URL:: 177 | 178 | ```py 179 | http://somedomain.com/urls-to-crawl/spider1/part1.list 180 | http://somedomain.com/urls-to-crawl/spider1/part2.list 181 | http://somedomain.com/urls-to-crawl/spider1/part3.list 182 | 183 | ``` 184 | 185 | 然后在3个不同的ScrapyD服务器上启动一个 Spider 运行。 Spider 会收到一个( Spider )论点 `part` 使用要爬网的分区的编号:: 186 | 187 | ```py 188 | curl http://scrapy1.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=1 189 | curl http://scrapy2.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=2 190 | curl http://scrapy3.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=3 191 | 192 | ``` 193 | 194 | ## 避免被禁止 195 | 196 | 一些网站实施了某些措施,以防止僵尸爬行他们,不同程度的复杂度。绕开这些措施既困难又棘手,有时可能需要特殊的基础设施。请考虑联系 [commercial support](https://scrapy.org/support/) 如果有疑问。 197 | 198 | 以下是处理此类网站时要记住的一些提示: 199 | 200 | * 将你的用户代理从浏览器中的一个著名的池中轮换出来(用google搜索以获得一个列表)。 201 | * 禁用cookies(请参见 [`COOKIES_ENABLED`](downloader-middleware.html#std:setting-COOKIES_ENABLED) )因为有些网站可能会使用cookie来发现机器人行为 202 | * 使用下载延迟(2或更高)。见 [`DOWNLOAD_DELAY`](settings.html#std:setting-DOWNLOAD_DELAY) 设置。 203 | * 如果可能,使用 [Google cache](http://www.googleguide.com/cached_pages.html) 获取页面,而不是直接访问站点 204 | * 使用一个旋转的IP池。例如,自由 [Tor project](https://www.torproject.org/) 或者像这样的付费服务 [ProxyMesh](https://proxymesh.com/) . 开源替代方案是 [scrapoxy](https://scrapoxy.io/) ,可以将自己的代理附加到的超级代理。 205 | * 使用一个在内部绕过BAN的高度分布式下载程序,这样您就可以专注于解析干净的页面。这种下载器的一个例子是 [Crawlera](https://scrapinghub.com/crawlera) 206 | 207 | 如果您仍然无法阻止您的bot被禁止,请考虑联系 [commercial support](https://scrapy.org/support/) . -------------------------------------------------------------------------------- /docs/31.md: -------------------------------------------------------------------------------- 1 | # 通用爬虫 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 碎片默认值针对爬行特定站点进行了优化。这些站点通常由一个残缺的 Spider 来处理,尽管这不是必需的或必需的(例如,有一些普通的 Spider 来处理任何向它们抛出的给定站点)。 6 | 7 | 除了这种“集中的爬行”之外,还有另一种常见的爬行类型,它覆盖了大量(可能是无限的)域,并且只受时间或其他任意约束的限制,而不是在域被爬行到完成或没有更多的请求执行时停止。这些被称为“宽爬虫”,是搜索引擎使用的典型爬虫。 8 | 9 | 这些是一些常见的特性,通常在广泛的爬行中发现: 10 | 11 | * 它们对许多域(通常是无边界的)而不是一组特定的站点进行爬网 12 | * 它们不一定要对域进行爬网直至完成,因为这样做是不切实际的(或不可能的),而是按已爬网的时间或页数限制爬网。 13 | * 它们在逻辑上更简单(而不是具有许多提取规则的非常复杂的spider),因为数据通常在单独的阶段进行后处理。 14 | * 它们同时对多个域进行爬网,这使得它们可以通过不受任何特定站点约束的限制来实现更快的爬网速度(每个站点的爬行速度都很慢,以尊重礼貌,但许多站点是并行进行的) 15 | 16 | 如上所述,Scrapy的默认设置是针对重点爬行而不是广泛爬行而优化的。然而,由于其异步体系结构,Scrapy非常适合执行快速的广泛爬行。本页总结了在使用Scrapy进行宽范围爬行时需要记住的一些事情,以及为实现高效的宽范围爬行而调整Scrapy设置的具体建议。 17 | 18 | ## 增加并发性 19 | 20 | Concurrency是并行处理的请求数。存在全局限制和每个域限制。 21 | 22 | scrapy中的默认全局并发限制不适用于并行地对许多不同的域进行爬网,因此您需要增加它。增加多少将取决于您的爬虫有多少CPU可用。一个好的起点是 `100` 但最好的方法是做一些试验,并确定零碎的进程在什么样的并发性上限制了CPU。为了获得最佳性能,您应该选择CPU使用率为80-90%的并发性。 23 | 24 | 要增加全局并发性,请使用: 25 | 26 | ```py 27 | CONCURRENT_REQUESTS = 100 28 | 29 | ``` 30 | 31 | ## 增加Twisted IO线程池的最大大小 32 | 33 | 目前scrapy使用线程池以阻塞方式进行DNS解析。如果并发性级别更高,则爬行速度可能会变慢,甚至无法达到DNS解析程序超时。增加处理DNS查询的线程数的可能解决方案。将更快地处理DNS队列,从而加快建立连接和整体爬行。 34 | 35 | 要增加最大线程池大小,请使用: 36 | 37 | ```py 38 | REACTOR_THREADPOOL_MAXSIZE = 20 39 | 40 | ``` 41 | 42 | ## 设置您自己的DNS 43 | 44 | 如果您有多个爬行进程和单个中心DNS,它会像DOS攻击DNS服务器一样,导致整个网络速度减慢,甚至阻塞您的机器。要避免这种情况,请使用本地缓存设置您自己的DNS服务器,并向某些大型DNS(如OpenDNS或Verizon)上游设置。 45 | 46 | ## 降低日志级别 47 | 48 | 当进行广泛的爬行时,你通常只对你得到的爬行率和发现的任何错误感兴趣。当使用 `INFO` 日志级别。为了保存CPU(和日志存储要求),不应使用 `DEBUG` 在生产中进行大型通用爬虫时的原木水平。使用 `DEBUG` 不过,在开发(广泛的)爬虫时,级别可能很好。 49 | 50 | 要设置日志级别,请使用: 51 | 52 | ```py 53 | LOG_LEVEL = 'INFO' 54 | 55 | ``` 56 | 57 | ## 禁用Cookie 58 | 59 | 禁用cookies,除非 _really_ 需要。在进行广泛的爬行时,通常不需要cookie(搜索引擎爬行器忽略它们),它们通过节省一些CPU周期和减少零碎爬行器的内存占用来提高性能。 60 | 61 | 要禁用cookie,请使用: 62 | 63 | ```py 64 | COOKIES_ENABLED = False 65 | 66 | ``` 67 | 68 | ## 禁用重试 69 | 70 | 重试失败的HTTP请求会大大降低爬行速度,特别是当站点原因响应速度非常慢(或失败)时,会导致超时错误,该错误会被多次不必要地重试,从而阻止爬行器容量被重新用于其他域。 71 | 72 | 要禁用重试,请使用: 73 | 74 | ```py 75 | RETRY_ENABLED = False 76 | 77 | ``` 78 | 79 | ## 减少下载超时 80 | 81 | 除非您是从一个非常慢的连接爬行(这不应该是广泛爬行的情况),否则请减少下载超时,以便快速丢弃卡住的请求并释放处理下一个请求的容量。 82 | 83 | 要减少下载超时,请使用: 84 | 85 | ```py 86 | DOWNLOAD_TIMEOUT = 15 87 | 88 | ``` 89 | 90 | ## 禁用重定向 91 | 92 | 考虑禁用重定向,除非您有兴趣跟踪它们。在进行广泛的爬行时,保存重定向并在以后的爬行中重新访问站点时解决重定向是很常见的。这也有助于保持每个爬网批处理的请求数不变,否则重定向循环可能会导致爬网程序在任何特定域上投入过多的资源。 93 | 94 | 要禁用重定向,请使用: 95 | 96 | ```py 97 | REDIRECT_ENABLED = False 98 | 99 | ``` 100 | 101 | ## 启用“Ajax可爬行页”的爬行 102 | 103 | 一些页面(根据2013年的经验数据,高达1%)宣称自己是 [ajax crawlable](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started) . 这意味着它们提供了内容的纯HTML版本,通常只能通过Ajax提供。页面可以用两种方式表示: 104 | 105 | 1. 通过使用 `#!` 在url中-这是默认方式; 106 | 2. 通过使用一个特殊的元标签-这种方式在“主”、“索引”网站页面上使用。 107 | 108 | 废料处理(1)自动;处理(2)启用 [AjaxCrawlMiddleware](downloader-middleware.html#ajaxcrawl-middleware) :: 109 | 110 | ```py 111 | AJAXCRAWL_ENABLED = True 112 | 113 | ``` 114 | 115 | 在进行广泛的爬行时,通常会对许多“索引”网页进行爬行;AjaxCrawl中间件有助于正确地对它们进行爬行。它在默认情况下是关闭的,因为它有一些性能开销,启用它进行聚焦爬行没有什么意义。 -------------------------------------------------------------------------------- /docs/32.md: -------------------------------------------------------------------------------- 1 | # 使用浏览器的开发人员工具进行抓取 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 下面是关于如何使用浏览器的开发人员工具来简化抓取过程的一般指南。现在几乎所有浏览器都内置了 [Developer Tools](https://en.wikipedia.org/wiki/Web_development_tools) 尽管我们将在本指南中使用firefox,但这些概念适用于任何其他浏览器。 6 | 7 | 在本指南中,我们将介绍通过抓取从浏览器的开发人员工具中使用的基本工具 [quotes.toscrape.com](http://quotes.toscrape.com) . 8 | 9 | ## 检查实时浏览器DOM时的注意事项 10 | 11 | 由于开发人员工具在一个活动的浏览器DOM上运行,所以在检查页面源代码时,您实际上看到的不是原始的HTML,而是应用了一些浏览器清理和执行javascript代码后修改的HTML。尤其是火狐,以添加 `<tbody>` 元素到表。另一方面,scrapy不修改原始页面html,因此如果使用 `<tbody>` 在xpath表达式中。 12 | 13 | 因此,您应该记住以下几点: 14 | 15 | * 检查DOM以查找要在Scrapy中使用的xpaths时禁用javascript(在“开发人员工具”设置中,单击 <cite>Disable JavaScript</cite>) 16 | * 不要使用完整的xpath路径,使用基于属性的相对路径和智能路径(例如 `id` , `class` , `width` 或任何识别特征,如 `contains(@href, 'image')` . 17 | * 从不包括 `<tbody>` xpath表达式中的元素,除非您真正知道自己在做什么 18 | 19 | ## 查看网站 20 | 21 | 到目前为止,开发人员工具最方便的特性是 <cite>Inspector</cite> 功能,允许您检查任何网页的基本HTML代码。为了演示检查员,让我们看看 [quotes.toscrape.com](http://quotes.toscrape.com) 现场。 22 | 23 | 在这个网站上,我们总共有来自不同作者的十个引用,其中有特定的标签,还有前十个标签。假设我们想要提取这个页面上的所有引用,而不需要任何关于作者、标签等的元信息。 24 | 25 | 我们不必查看页面的整个源代码,只需右键单击一个报价并选择 `Inspect Element (Q)` 打开了 <cite>Inspector</cite>. 在里面你应该看到这样的东西: 26 | 27 | [![Firefox's Inspector-tool](img/6d09274a6a0eadb4fac81ff1bd508248.jpg)](../_images/inspector_01.png) 28 | 29 | 我们感兴趣的是: 30 | 31 | ```py 32 |
33 | (...) 34 | (...) 35 |
(...)
36 |
37 | 38 | ``` 39 | 40 | 如果你在第一个上面徘徊 `div` 正上方 `span` 在屏幕截图中突出显示的标签,您将看到网页的相应部分也会突出显示。现在我们有了一个部分,但是我们在任何地方都找不到报价文本。 41 | 42 | 的优势 <cite>Inspector</cite> 它自动展开和折叠网页的部分和标签,大大提高了可读性。您可以通过单击标签前面的箭头或直接双击标签来展开和折叠标签。如果我们扩大 `span` 带标签 `class= "text"` 我们将看到我们单击的报价文本。这个 <cite>Inspector</cite> 允许将xpaths复制到选定元素。让我们试试看:右键单击 `span` 选择标记 `Copy > XPath` 然后像这样把它贴在破壳里: 43 | 44 | ```py 45 | $ scrapy shell "http://quotes.toscrape.com/" 46 | (...) 47 | >>> response.xpath('/html/body/div/div[2]/div[1]/div[1]/span[1]/text()').getall() 48 | ['"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”] 49 | 50 | ``` 51 | 52 | 添加 `text()` 最后,我们可以用这个基本选择器提取第一个报价。但这个xpath并没有那么聪明。它所做的就是在源代码中沿着所需的路径从 `html` . 那么让我们看看我们是否可以改进一下xpath: 53 | 54 | 如果我们检查 <cite>Inspector</cite> 我们将再次看到,在我们的 `div` 标签我们有九个相同的 `div` 标签,每个标签都具有与第一个相同的属性。如果我们扩展其中任何一个,我们将看到与第一个报价相同的结构:两个 `span` 标签和一个 `div` 标签。我们可以扩大每个 `span` 带标签 `class="text"` 在我们内部 `div` 标记并查看每个引用: 55 | 56 | ```py 57 |
58 | 59 | “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” 60 | 61 | (...) 62 |
(...)
63 |
64 | 65 | ``` 66 | 67 | 有了这些知识,我们可以改进我们的xpath:我们只需选择 `span` 标签与 `class="text"` 通过使用 [has-class-extension](https://parsel.readthedocs.io/en/latest/usage.html#other-xpath-extensions) :: 68 | 69 | ```py 70 | >>> response.xpath('//span[has-class("text")]/text()').getall() 71 | ['"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”, 72 | '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 73 | '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”', 74 | (...)] 75 | 76 | ``` 77 | 78 | 通过一个简单、更聪明的xpath,我们能够从页面中提取所有的引号。我们可以在第一个xpath上构建一个循环,以增加最后一个xpath的数量。 `div` ,但这将不必要地复杂,只需使用 `has-class("text")` 我们能够在一行中提取所有报价。 79 | 80 | 这个 <cite>Inspector</cite> 还有很多其他有用的功能,比如在源代码中搜索或者直接滚动到您选择的元素。让我们演示一个用例: 81 | 82 | 说你想找到 `Next` 页面上的按钮。类型 `Next` 在搜索栏的右上角 <cite>Inspector</cite>. 你应该得到两个结果。第一个是 `li` 带标签 `class="text"` ,第二个是 `a` 标签。右键单击 `a` 标记与选择 `Scroll into View` . 如果您将鼠标悬停在标签上,您将看到突出显示的按钮。从这里我们可以很容易地创建一个 [Link Extractor](link-extractors.html#topics-link-extractors) 跟随分页。在这样一个简单的站点上,可能不需要从视觉上查找元素,而是 `Scroll into View` 函数在复杂的站点上非常有用。 83 | 84 | 请注意,搜索栏也可用于搜索和测试CSS选择器。例如,您可以搜索 `span.text` 查找所有报价文本。而不是全文搜索,这将搜索 `span` 带标签 `class="text"` 在页面中。 85 | 86 | ## 网络工具 87 | 88 | 在抓取过程中,您可能会遇到动态网页,其中页面的某些部分是通过多个请求动态加载的。虽然这很棘手,但是 <cite>Network</cite>- 开发人员工具中的工具大大简化了这项任务。为了演示网络工具,让我们看一下页面 [quotes.toscrape.com/scroll](quotes.toscrape.com/scroll/) . 89 | 90 | 页面与基本页面非常相似 [quotes.toscrape.com](http://quotes.toscrape.com) -第页,但不是上面提到的 `Next` 按钮,当您滚动到底部时,页面会自动加载新的引号。我们可以继续直接尝试不同的xpaths,但是我们将检查另一个非常有用的命令,来自scriby shell:: 91 | 92 | ```py 93 | $ scrapy shell "quotes.toscrape.com/scroll" 94 | (...) 95 | >>> view(response) 96 | 97 | ``` 98 | 99 | 浏览器窗口应该和网页一起打开,但有一个关键的区别:我们看到的不是引用,而是一个带单词的绿色条。 `Loading...` . 100 | 101 | [![Response from quotes.toscrape.com/scroll](img/ebf6f0b54b0530b158ca080658e3473d.jpg)](../_images/network_01.png) 102 | 103 | 这个 `view(response)` 命令让我们查看shell或稍后 Spider 从服务器接收到的响应。这里我们看到加载了一些基本模板,其中包括标题、登录按钮和页脚,但是缺少引号。这告诉我们报价是从不同的请求加载的,而不是 `quotes.toscrape/scroll` . 104 | 105 | 如果你点击 `Network` 选项卡,您可能只能看到两个条目。我们要做的第一件事是通过单击 `Persist Logs` . 如果禁用此选项,则每次导航到不同的页面时,日志都会自动清除。启用这个选项是一个很好的默认设置,因为它可以让我们控制何时清除日志。 106 | 107 | 如果我们现在重新加载页面,您将看到日志中填充了六个新的请求。 108 | 109 | [![Network tab with persistent logs and requests](img/d3df2a33256732c3bb420ea930dbda9a.jpg)](../_images/network_02.png) 110 | 111 | 在这里,我们可以看到在重新加载页面时发出的每个请求,并且可以检查每个请求及其响应。因此,让我们找出我们的报价来自哪里: 112 | 113 | 首先单击带有名称的请求 `scroll` . 在右边,您现在可以检查请求。在 `Headers` 您将找到有关请求头的详细信息,例如URL、方法、IP地址等。我们将忽略其他选项卡并直接单击 `Reponse` . 114 | 115 | 你应该在里面看到什么 `Preview` 窗格是呈现的HTML代码,这正是我们调用 `view(response)` 在贝壳里。相应地 `type` 日志中的请求为 `html` . 其他请求的类型如下 `css` 或 `js` 但是我们感兴趣的是一个要求 `quotes?page=1` 与类型 `json` . 116 | 117 | 如果我们点击这个请求,我们会看到请求的URL是 `http://quotes.toscrape.com/api/quotes?page=1` 响应是一个包含我们的引号的JSON对象。我们也可以右键单击请求并打开 `Open in new tab` 以获得更好的概述。 118 | 119 | [![JSON-object returned from the quotes.toscrape API](img/fca494eacecdaeee595ae572e32d80d2.jpg)](../_images/network_03.png) 120 | 121 | 有了这个响应,我们现在可以轻松地解析JSON对象,并请求每个页面获取站点上的每个引用: 122 | 123 | ```py 124 | import scrapy 125 | import json 126 | 127 | class QuoteSpider(scrapy.Spider): 128 | name = 'quote' 129 | allowed_domains = ['quotes.toscrape.com'] 130 | page = 1 131 | start_urls = ['http://quotes.toscrape.com/api/quotes?page=1'] 132 | 133 | def parse(self, response): 134 | data = json.loads(response.text) 135 | for quote in data["quotes"]: 136 | yield {"quote": quote["text"]} 137 | if data["has_next"]: 138 | self.page += 1 139 | url = "http://quotes.toscrape.com/api/quotes?page={}".format(self.page) 140 | yield scrapy.Request(url=url, callback=self.parse) 141 | 142 | ``` 143 | 144 | 这个 Spider 程序从QuotesAPI的第一页开始。对于每个响应,我们分析 `response.text` 并分配给 `data` . 这让我们可以像在Python字典上一样对JSON对象进行操作。我们迭代 `quotes` 打印出 `quote["text"]` . 如果方便的话 `has_next` 元素是 `true` (尝试加载 [quotes.toscrape.com/api/quotes?page=10](http://quotes.toscrape.com/api/quotes?page=10) 在您的浏览器或大于10的页码中,我们增加 `page` 属性与 `yield` 一个新的请求,将递增的页码插入到 `url` . 145 | 146 | 你可以看到,在 <cite>Network</cite>- 工具我们能够轻松地复制页面滚动功能的动态请求。对动态页面进行爬行可能非常困难,页面也可能非常复杂,但是(主要)归根结底就是识别正确的请求并在 Spider 中复制它。 -------------------------------------------------------------------------------- /docs/33.md: -------------------------------------------------------------------------------- 1 | # 调试内存泄漏 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 在Scrapy中,请求、响应和项目等对象的生命周期是有限的:它们被创建、使用一段时间,最后被销毁。 6 | 7 | 从所有这些对象中,请求可能是生命周期最长的请求,因为它一直在调度程序队列中等待,直到需要处理它为止。有关详细信息,请参阅 [体系结构概述](architecture.html#topics-architecture) . 8 | 9 | 由于这些零碎的物体有(相当长的)寿命,总有在没有正确释放它们的情况下将它们累积到内存中的风险,从而导致所谓的“内存泄漏”。 10 | 11 | 为了帮助调试内存泄漏,scrapy提供了一种内置机制,用于跟踪调用的对象引用 [trackref](#topics-leaks-trackrefs) ,您还可以使用第三方库 [Guppy](#topics-leaks-guppy) 有关更高级的内存调试(请参阅下面的详细信息)。两种机制都必须从 [Telnet Console](telnetconsole.html#topics-telnetconsole) . 12 | 13 | ## 内存泄漏的常见原因 14 | 15 | Scrapy开发人员传递请求中引用的对象(例如,使用 [`meta`](request-response.html#scrapy.http.Request.meta "scrapy.http.Request.meta") 属性或请求回调函数),它有效地将这些引用对象的生存期限制为请求的生存期。到目前为止,这是导致零碎项目内存泄漏的最常见原因,对于新手来说,这是一个很难调试的原因。 16 | 17 | 在大型项目中, Spider 通常是由不同的人编写的,其中一些 Spider 可能会“泄漏”,从而在其他(写得好的) Spider 同时运行时影响其他 Spider ,而这反过来又会影响整个爬行过程。 18 | 19 | 如果您没有正确地释放(以前分配的)资源,那么泄漏也可能来自您编写的定制中间件、管道或扩展。例如,在上分配资源 [`spider_opened`](signals.html#std:signal-spider_opened) 但不释放它们 [`spider_closed`](signals.html#std:signal-spider_closed) 如果你跑步,可能会引起问题 [multiple spiders per process](practices.html#run-multiple-spiders) . 20 | 21 | ### 请求太多? 22 | 23 | 默认情况下,scrapy将请求队列保存在内存中;它包括 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 对象和请求属性中引用的所有对象(例如 [`meta`](request-response.html#scrapy.http.Request.meta "scrapy.http.Request.meta") )虽然不一定是泄漏,但这可能会占用大量内存。有可能 [persistent job queue](jobs.html#topics-jobs) 有助于控制内存使用。 24 | 25 | ## 使用调试内存泄漏 `trackref` 26 | 27 | `trackref` 是Scrapy提供的一个模块,用于调试最常见的内存泄漏情况。它基本上跟踪对所有活动请求、响应、项和选择器对象的引用。 28 | 29 | 您可以进入telnet控制台并使用 `prefs()` 函数的别名 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 功能: 30 | 31 | ```py 32 | telnet localhost 6023 33 | 34 | >>> prefs() 35 | Live References 36 | 37 | ExampleSpider 1 oldest: 15s ago 38 | HtmlResponse 10 oldest: 1s ago 39 | Selector 2 oldest: 0s ago 40 | FormRequest 878 oldest: 7s ago 41 | 42 | ``` 43 | 44 | 如您所见,该报告还显示了每个类中最旧对象的“年龄”。如果每个进程运行多个spider,那么通过查看最早的请求或响应,您很可能会发现哪个spider正在泄漏。您可以使用 [`get_oldest()`](#scrapy.utils.trackref.get_oldest "scrapy.utils.trackref.get_oldest") 功能(从telnet控制台)。 45 | 46 | ### 跟踪哪些对象? 47 | 48 | 被跟踪的对象 `trackrefs` 都来自这些类(及其所有子类): 49 | 50 | * [`scrapy.http.Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 51 | * [`scrapy.http.Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 52 | * [`scrapy.item.Item`](items.html#scrapy.item.Item "scrapy.item.Item") 53 | * [`scrapy.selector.Selector`](selectors.html#scrapy.selector.Selector "scrapy.selector.Selector") 54 | * [`scrapy.spiders.Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") 55 | 56 | ### 一个真实的例子 57 | 58 | 让我们来看一个假设的内存泄漏案例的具体示例。假设我们有一只 Spider ,上面有一条和这条类似的线: 59 | 60 | ```py 61 | return Request("http://www.somenastyspider.com/product.php?pid=%d" % product_id, 62 | callback=self.parse, meta={referer: response}) 63 | 64 | ``` 65 | 66 | 该行正在请求中传递一个响应引用,它有效地将响应生命周期与请求的生命周期联系起来,这肯定会导致内存泄漏。 67 | 68 | 让我们看看如何通过使用 `trackref` 工具。 69 | 70 | 当爬虫运行几分钟后,我们注意到它的内存使用量增长了很多,我们可以进入它的telnet控制台并检查实时引用: 71 | 72 | ```py 73 | >>> prefs() 74 | Live References 75 | 76 | SomenastySpider 1 oldest: 15s ago 77 | HtmlResponse 3890 oldest: 265s ago 78 | Selector 2 oldest: 0s ago 79 | Request 3878 oldest: 250s ago 80 | 81 | ``` 82 | 83 | 事实上,存在如此多的实时响应(而且它们太老了),这是绝对可疑的,因为与请求相比,响应的生存期应该相对较短。响应的数量与请求的数量相似,因此看起来它们是以某种方式捆绑在一起的。我们现在可以检查 Spider 的代码,以发现产生泄漏的讨厌的行(在请求中传递响应引用)。 84 | 85 | 有时,关于活动对象的额外信息可能会有所帮助。让我们检查最早的响应: 86 | 87 | ```py 88 | >>> from scrapy.utils.trackref import get_oldest 89 | >>> r = get_oldest('HtmlResponse') 90 | >>> r.url 91 | 'http://www.somenastyspider.com/product.php?pid=123' 92 | 93 | ``` 94 | 95 | 如果您希望遍历所有对象,而不是获取最旧的对象,则可以使用 [`scrapy.utils.trackref.iter_all()`](#scrapy.utils.trackref.iter_all "scrapy.utils.trackref.iter_all") 功能: 96 | 97 | ```py 98 | >>> from scrapy.utils.trackref import iter_all 99 | >>> [r.url for r in iter_all('HtmlResponse')] 100 | ['http://www.somenastyspider.com/product.php?pid=123', 101 | 'http://www.somenastyspider.com/product.php?pid=584', 102 | ... 103 | 104 | ``` 105 | 106 | ### Spider 太多了? 107 | 108 | 如果项目并行执行的spider太多,则 `prefs()` 很难阅读。因此,该函数具有 `ignore` 可用于忽略特定类(及其所有子类)的参数。例如,这不会显示任何对 Spider 的实时引用: 109 | 110 | ```py 111 | >>> from scrapy.spiders import Spider 112 | >>> prefs(ignore=Spider) 113 | 114 | ``` 115 | 116 | ### scrapy.utils.trackRef模块 117 | 118 | 以下是 [`trackref`](#module-scrapy.utils.trackref "scrapy.utils.trackref: Track references of live objects") 模块。 119 | 120 | ```py 121 | class scrapy.utils.trackref.object_ref 122 | ``` 123 | 124 | 如果要使用跟踪活动实例,请从此类(而不是对象)继承 `trackref` 模块。 125 | 126 | ```py 127 | scrapy.utils.trackref.print_live_refs(class_name, ignore=NoneType) 128 | ``` 129 | 130 | 打印实时引用的报告,按类名分组。 131 | 132 | | 参数: | **ignore** (_class_ _or_ _classes tuple_) -- 如果给定,则将忽略指定类(或类的元组)中的所有对象。 | 133 | | --- | --- | 134 | 135 | ```py 136 | scrapy.utils.trackref.get_oldest(class_name) 137 | ``` 138 | 139 | 返回具有给定类名的最旧活动对象,或者 `None` 如果没有找到。使用 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 首先获取每个类名的所有跟踪活动对象的列表。 140 | 141 | ```py 142 | scrapy.utils.trackref.iter_all(class_name) 143 | ``` 144 | 145 | 返回具有给定类名的所有活动对象的迭代器,或者 `None` 如果没有找到。使用 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 首先获取每个类名的所有跟踪活动对象的列表。 146 | 147 | ## 用Guppy调试内存泄漏 148 | 149 | `trackref` 为跟踪内存泄漏提供了非常方便的机制,但它只跟踪更可能导致内存泄漏的对象(请求、响应、项和选择器)。但是,还有其他一些情况,内存泄漏可能来自其他(或多或少是模糊的)对象。如果这是你的情况,你不能用 `trackref` ,您还有另一个资源: [Guppy library](https://pypi.python.org/pypi/guppy). If you're using Python3, see [用muppy调试内存泄漏](#topics-leaks-muppy). 150 | 151 | 如果你使用 `pip` ,可以使用以下命令安装Guppy:: 152 | 153 | ```py 154 | pip install guppy 155 | 156 | ``` 157 | 158 | telnet控制台还提供内置的快捷方式( `hpy` )用于访问Guppy堆对象。下面是一个使用guppy查看堆中所有可用python对象的示例: 159 | 160 | ```py 161 | >>> x = hpy.heap() 162 | >>> x.bytype 163 | Partition of a set of 297033 objects. Total size = 52587824 bytes. 164 | Index Count % Size % Cumulative % Type 165 | 0 22307 8 16423880 31 16423880 31 dict 166 | 1 122285 41 12441544 24 28865424 55 str 167 | 2 68346 23 5966696 11 34832120 66 tuple 168 | 3 227 0 5836528 11 40668648 77 unicode 169 | 4 2461 1 2222272 4 42890920 82 type 170 | 5 16870 6 2024400 4 44915320 85 function 171 | 6 13949 5 1673880 3 46589200 89 types.CodeType 172 | 7 13422 5 1653104 3 48242304 92 list 173 | 8 3735 1 1173680 2 49415984 94 _sre.SRE_Pattern 174 | 9 1209 0 456936 1 49872920 95 scrapy.http.headers.Headers 175 | <1676 more rows. Type e.g. '_.more' to view.> 176 | 177 | ``` 178 | 179 | 你可以看到大多数空间都是听写使用的。然后,如果要查看引用这些dict的属性,可以执行以下操作: 180 | 181 | ```py 182 | >>> x.bytype[0].byvia 183 | Partition of a set of 22307 objects. Total size = 16423880 bytes. 184 | Index Count % Size % Cumulative % Referred Via: 185 | 0 10982 49 9416336 57 9416336 57 '.__dict__' 186 | 1 1820 8 2681504 16 12097840 74 '.__dict__', '.func_globals' 187 | 2 3097 14 1122904 7 13220744 80 188 | 3 990 4 277200 2 13497944 82 "['cookies']" 189 | 4 987 4 276360 2 13774304 84 "['cache']" 190 | 5 985 4 275800 2 14050104 86 "['meta']" 191 | 6 897 4 251160 2 14301264 87 '[2]' 192 | 7 1 0 196888 1 14498152 88 "['moduleDict']", "['modules']" 193 | 8 672 3 188160 1 14686312 89 "['cb_kwargs']" 194 | 9 27 0 155016 1 14841328 90 '[1]' 195 | <333 more rows. Type e.g. '_.more' to view.> 196 | 197 | ``` 198 | 199 | 正如您所看到的,Guppy模块非常强大,但也需要对Python内部结构有一些深入的了解。有关Guppy的更多信息,请参阅 [Guppy documentation](http://guppy-pe.sourceforge.net/) . 200 | 201 | ## 用muppy调试内存泄漏 202 | 203 | 如果您使用的是python 3,那么可以使用muppy [Pympler](https://pypi.org/project/Pympler/) . 204 | 205 | 如果你使用 `pip` ,可以使用以下命令安装muppy:: 206 | 207 | ```py 208 | pip install Pympler 209 | 210 | ``` 211 | 212 | 下面是一个使用muppy查看堆中所有可用python对象的示例: 213 | 214 | ```py 215 | >>> from pympler import muppy 216 | >>> all_objects = muppy.get_objects() 217 | >>> len(all_objects) 218 | 28667 219 | >>> from pympler import summary 220 | >>> suml = summary.summarize(all_objects) 221 | >>> summary.print_(suml) 222 | types | # objects | total size 223 | ==================================== | =========== | ============ 224 | _不幸的是,这个补丁只能在竞技场中不再分配对象的情况下释放竞技场。这意味着碎片化是一个大问题。一个应用程序可以有许多兆字节的空闲内存,分散在所有的区域中,但是它将无法释放其中的任何一个。这是所有内存分配器都遇到的问题。解决这个问题的唯一方法是移动到一个压缩垃圾收集器,它能够移动内存中的对象。这需要对python解释器进行重大更改。_ 255 | 256 | 为了保持内存消耗合理,可以将作业拆分为几个较小的作业或启用 [persistent job queue](jobs.html#topics-jobs) 不时停止/启动Spider。 -------------------------------------------------------------------------------- /docs/35.md: -------------------------------------------------------------------------------- 1 | # 部署 Spider 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 本节描述了部署 Scrapy Spider 以定期运行它们的不同选项。在您的本地机器中运行碎片 Spider 对于(早期)开发阶段非常方便,但是当您需要执行长时间运行的 Spider 或移动 Spider 以在生产中连续运行时,就不那么方便了。这就是部署 Scrapy Spider 的解决方案。 6 | 7 | 部署 Scrapy Spider 的常见选择是: 8 | 9 | * [Scrapyd](#deploy-scrapyd) (开放源代码) 10 | * [Scrapy Cloud](#deploy-scrapy-cloud) (基于云的) 11 | 12 | ## 部署到ScrapyD服务器 13 | 14 | [Scrapyd](https://github.com/scrapy/scrapyd) 是一个开放源码的应用程序,可以运行碎片 Spider 。它为服务器提供了HTTP API,能够运行和监视碎片 Spider 。 15 | 16 | 要将spiders部署到scrapyD,可以使用由提供的scrapyD部署工具 [scrapyd-client](https://github.com/scrapy/scrapyd-client) 包。请参阅 [scrapyd-deploy documentation](https://scrapyd.readthedocs.io/en/latest/deploy.html) 更多信息。 17 | 18 | ScrapyD由一些Scrapy开发人员维护。 19 | 20 | ## 部署到碎片云 21 | 22 | [Scrapy Cloud](https://scrapinghub.com/scrapy-cloud) 是基于云的托管服务 [Scrapinghub](https://scrapinghub.com/) 斯普利背后的公司。 23 | 24 | ScrapyCloud消除了设置和监视服务器的需要,并提供了一个很好的用户界面来管理spider和查看被刮走的项目、日志和统计信息。 25 | 26 | 要将 Spider 部署到碎片云,可以使用 [shub](https://doc.scrapinghub.com/shub.html) 命令行工具。请参阅 [Scrapy Cloud documentation](https://doc.scrapinghub.com/scrapy-cloud.html) 更多信息。 27 | 28 | Scrapy Cloud与ScrapyD兼容,您可以根据需要在它们之间进行切换-配置从 `scrapy.cfg` 文件就像 `scrapyd-deploy` . -------------------------------------------------------------------------------- /docs/36.md: -------------------------------------------------------------------------------- 1 | # AutoThrottle 扩展 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 这是一个扩展,基于Scrapy服务器和您正在爬行的网站的负载,自动限制爬行速度。 6 | 7 | ## 设计目标 8 | 9 | 1. 对站点更好,而不是使用默认的下载延迟为零 10 | 2. 自动调整碎片到最佳的爬行速度,这样用户就不必调整下载延迟来找到最佳的。用户只需要指定它允许的最大并发请求,扩展就可以完成其余的工作。 11 | 12 | ## 它是如何工作的 13 | 14 | AutoThrottle 扩展动态调整下载延迟,使 Spider 发送 [`AUTOTHROTTLE_TARGET_CONCURRENCY`](#std:setting-AUTOTHROTTLE_TARGET_CONCURRENCY) 平均每个远程网站的并发请求。 15 | 16 | 它使用下载延迟来计算延迟。主要思想如下:如果服务器需要 `latency` 响应时间为秒,客户端应每秒钟发送一个请求 `latency/N` 秒有 `N` 并行处理的请求。 17 | 18 | 不需要调整延迟,只需设置一个小的固定下载延迟,并对使用 [`CONCURRENT_REQUESTS_PER_DOMAIN`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_DOMAIN) 或 [`CONCURRENT_REQUESTS_PER_IP`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_IP) 选项。它会产生类似的效果,但有一些重要的区别: 19 | 20 | * 因为下载延迟很小,偶尔会有突发的请求; 21 | * 通常,非200(错误)响应的返回速度比常规响应快,因此,只要有一个较小的下载延迟和硬并发限制,当服务器开始返回错误时,爬虫程序将更快地向服务器发送请求。但这与爬虫应该做的相反——如果出现错误,放慢速度更有意义:这些错误可能是由高请求率引起的。 22 | 23 | AutoThrottle 没有这些问题。 24 | 25 | ## 节流算法 26 | 27 | AutoThrottle 算法根据以下规则调整下载延迟: 28 | 29 | 1. Spider 总是以下载延迟开始 [`AUTOTHROTTLE_START_DELAY`](#std:setting-AUTOTHROTTLE_START_DELAY) ; 30 | 2. 当收到响应时,目标下载延迟计算为 `latency / N` 在哪里? `latency` 是响应的延迟,并且 `N` 是 [`AUTOTHROTTLE_TARGET_CONCURRENCY`](#std:setting-AUTOTHROTTLE_TARGET_CONCURRENCY) . 31 | 3. 下一个请求的下载延迟设置为上一个下载延迟和目标下载延迟的平均值; 32 | 4. 不允许非200响应的延迟减少延迟; 33 | 5. 下载延迟不能小于 [`DOWNLOAD_DELAY`](settings.html#std:setting-DOWNLOAD_DELAY) 或大于 [`AUTOTHROTTLE_MAX_DELAY`](#std:setting-AUTOTHROTTLE_MAX_DELAY) 34 | 35 | 注解 36 | 37 | autothrottle扩展支持并发和延迟的标准碎片设置。这意味着它将尊重 [`CONCURRENT_REQUESTS_PER_DOMAIN`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_DOMAIN) 和 [`CONCURRENT_REQUESTS_PER_IP`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_IP) 选项,并且从不将下载延迟设置为低于 [`DOWNLOAD_DELAY`](settings.html#std:setting-DOWNLOAD_DELAY) . 38 | 39 | 在scrappy中,下载延迟是以建立TCP连接和接收HTTP头之间所经过的时间来度量的。 40 | 41 | 注意,在一个合作的多任务环境中,这些延迟很难精确测量,因为scrapy可能正忙于处理spider回调,例如,无法参加下载。然而,这些延迟仍然应该对Scrapy(最终是服务器)有多忙给出一个合理的估计,并且这个扩展是在这个前提下构建的。 42 | 43 | ## 设置 44 | 45 | 用于控制 AutoThrottle 扩展的设置为: 46 | 47 | * [`AUTOTHROTTLE_ENABLED`](#std:setting-AUTOTHROTTLE_ENABLED) 48 | * [`AUTOTHROTTLE_START_DELAY`](#std:setting-AUTOTHROTTLE_START_DELAY) 49 | * [`AUTOTHROTTLE_MAX_DELAY`](#std:setting-AUTOTHROTTLE_MAX_DELAY) 50 | * [`AUTOTHROTTLE_TARGET_CONCURRENCY`](#std:setting-AUTOTHROTTLE_TARGET_CONCURRENCY) 51 | * [`AUTOTHROTTLE_DEBUG`](#std:setting-AUTOTHROTTLE_DEBUG) 52 | * [`CONCURRENT_REQUESTS_PER_DOMAIN`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_DOMAIN) 53 | * [`CONCURRENT_REQUESTS_PER_IP`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_IP) 54 | * [`DOWNLOAD_DELAY`](settings.html#std:setting-DOWNLOAD_DELAY) 55 | 56 | 有关详细信息,请参阅 [它是如何工作的](#autothrottle-algorithm) . 57 | 58 | ### AUTOTHROTTLE_ENABLED 59 | 60 | 违约: `False` 61 | 62 | 启用AutoThrottle 扩展。 63 | 64 | ### AUTOTHROTTLE_START_DELAY 65 | 66 | 违约: `5.0` 67 | 68 | 初始下载延迟(秒)。 69 | 70 | ### AUTOTHROTTLE_MAX_DELAY 71 | 72 | 违约: `60.0` 73 | 74 | 在高延迟情况下设置的最大下载延迟(秒)。 75 | 76 | ### AUTOTHROTTLE_TARGET_CONCURRENCY 77 | 78 | 1.1 新版功能. 79 | 80 | 违约: `1.0` 81 | 82 | Scrapy的平均请求数应与远程网站并行发送。 83 | 84 | 默认情况下,autothrottle会调整延迟以向每个远程网站发送单个并发请求。将此选项设置为更高的值(例如 `2.0` )以增加远程服务器的吞吐量和负载。下层 `AUTOTHROTTLE_TARGET_CONCURRENCY` 价值(例如) `0.5` )让爬虫人更加保守和礼貌。 85 | 86 | 注意 [`CONCURRENT_REQUESTS_PER_DOMAIN`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_DOMAIN) 和 [`CONCURRENT_REQUESTS_PER_IP`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_IP) 启用 AutoThrottle 扩展功能时,仍会遵循选项。这意味着如果 `AUTOTHROTTLE_TARGET_CONCURRENCY` 设置为大于的值 [`CONCURRENT_REQUESTS_PER_DOMAIN`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_DOMAIN) 或 [`CONCURRENT_REQUESTS_PER_IP`](settings.html#std:setting-CONCURRENT_REQUESTS_PER_IP) ,爬虫程序将无法达到此数量的并发请求。 87 | 88 | 在每个给定的时间点上,scrapy可以发送的并发请求多于或少于 `AUTOTHROTTLE_TARGET_CONCURRENCY` ;这是爬虫尝试接近的建议值,而不是硬限制。 89 | 90 | ### AUTOTHROTTLE_DEBUG 91 | 92 | 违约: `False` 93 | 94 | 启用 AutoThrottle 调试模式,该模式将显示收到的每个响应的统计信息,以便您可以看到如何实时调整节流参数。 -------------------------------------------------------------------------------- /docs/37.md: -------------------------------------------------------------------------------- 1 | # Benchmarking 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 0.17 新版功能. 6 | 7 | Scrapy提供了一个简单的基准测试套件,可以生成一个本地HTTP服务器并以最大可能的速度爬行。这个基准测试的目标是了解Scrapy在硬件中的表现,以便有一个共同的比较基准。它使用一个简单的 Spider ,它不做任何事情,只跟踪链接。 8 | 9 | 使用它:: 10 | 11 | ```py 12 | scrapy bench 13 | 14 | ``` 15 | 16 | 您应该看到这样的输出: 17 | 18 | ```py 19 | 2016-12-16 21:18:48 [scrapy.utils.log] INFO: Scrapy 1.2.2 started (bot: quotesbot) 20 | 2016-12-16 21:18:48 [scrapy.utils.log] INFO: Overridden settings: {'CLOSESPIDER_TIMEOUT': 10, 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['quotesbot.spiders'], 'LOGSTATS_INTERVAL': 1, 'BOT_NAME': 'quotesbot', 'LOG_LEVEL': 'INFO', 'NEWSPIDER_MODULE': 'quotesbot.spiders'} 21 | 2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled extensions: 22 | ['scrapy.extensions.closespider.CloseSpider', 23 | 'scrapy.extensions.logstats.LogStats', 24 | 'scrapy.extensions.telnet.TelnetConsole', 25 | 'scrapy.extensions.corestats.CoreStats'] 26 | 2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled downloader middlewares: 27 | ['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware', 28 | 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware', 29 | 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware', 30 | 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware', 31 | 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware', 32 | 'scrapy.downloadermiddlewares.retry.RetryMiddleware', 33 | 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware', 34 | 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware', 35 | 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware', 36 | 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware', 37 | 'scrapy.downloadermiddlewares.stats.DownloaderStats'] 38 | 2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled spider middlewares: 39 | ['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware', 40 | 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware', 41 | 'scrapy.spidermiddlewares.referer.RefererMiddleware', 42 | 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware', 43 | 'scrapy.spidermiddlewares.depth.DepthMiddleware'] 44 | 2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled item pipelines: 45 | [] 46 | 2016-12-16 21:18:49 [scrapy.core.engine] INFO: Spider opened 47 | 2016-12-16 21:18:49 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 48 | 2016-12-16 21:18:50 [scrapy.extensions.logstats] INFO: Crawled 70 pages (at 4200 pages/min), scraped 0 items (at 0 items/min) 49 | 2016-12-16 21:18:51 [scrapy.extensions.logstats] INFO: Crawled 134 pages (at 3840 pages/min), scraped 0 items (at 0 items/min) 50 | 2016-12-16 21:18:52 [scrapy.extensions.logstats] INFO: Crawled 198 pages (at 3840 pages/min), scraped 0 items (at 0 items/min) 51 | 2016-12-16 21:18:53 [scrapy.extensions.logstats] INFO: Crawled 254 pages (at 3360 pages/min), scraped 0 items (at 0 items/min) 52 | 2016-12-16 21:18:54 [scrapy.extensions.logstats] INFO: Crawled 302 pages (at 2880 pages/min), scraped 0 items (at 0 items/min) 53 | 2016-12-16 21:18:55 [scrapy.extensions.logstats] INFO: Crawled 358 pages (at 3360 pages/min), scraped 0 items (at 0 items/min) 54 | 2016-12-16 21:18:56 [scrapy.extensions.logstats] INFO: Crawled 406 pages (at 2880 pages/min), scraped 0 items (at 0 items/min) 55 | 2016-12-16 21:18:57 [scrapy.extensions.logstats] INFO: Crawled 438 pages (at 1920 pages/min), scraped 0 items (at 0 items/min) 56 | 2016-12-16 21:18:58 [scrapy.extensions.logstats] INFO: Crawled 470 pages (at 1920 pages/min), scraped 0 items (at 0 items/min) 57 | 2016-12-16 21:18:59 [scrapy.core.engine] INFO: Closing spider (closespider_timeout) 58 | 2016-12-16 21:18:59 [scrapy.extensions.logstats] INFO: Crawled 518 pages (at 2880 pages/min), scraped 0 items (at 0 items/min) 59 | 2016-12-16 21:19:00 [scrapy.statscollectors] INFO: Dumping Scrapy stats: 60 | {'downloader/request_bytes': 229995, 61 | 'downloader/request_count': 534, 62 | 'downloader/request_method_count/GET': 534, 63 | 'downloader/response_bytes': 1565504, 64 | 'downloader/response_count': 534, 65 | 'downloader/response_status_count/200': 534, 66 | 'finish_reason': 'closespider_timeout', 67 | 'finish_time': datetime.datetime(2016, 12, 16, 16, 19, 0, 647725), 68 | 'log_count/INFO': 17, 69 | 'request_depth_max': 19, 70 | 'response_received_count': 534, 71 | 'scheduler/dequeued': 533, 72 | 'scheduler/dequeued/memory': 533, 73 | 'scheduler/enqueued': 10661, 74 | 'scheduler/enqueued/memory': 10661, 75 | 'start_time': datetime.datetime(2016, 12, 16, 16, 18, 49, 799869)} 76 | 2016-12-16 21:19:00 [scrapy.core.engine] INFO: Spider closed (closespider_timeout) 77 | 78 | ``` 79 | 80 | 这说明Scrapy可以在运行它的硬件中每分钟爬行大约3000页。请注意,这是一个非常简单的spider,用于跟踪链接,您编写的任何自定义spider都可能执行更多的操作,从而导致较慢的爬行速度。速度有多慢取决于你的 Spider 做了多少,写得有多好。 81 | 82 | 将来,更多的案例将添加到基准套件中,以涵盖其他常见场景。 -------------------------------------------------------------------------------- /docs/38.md: -------------------------------------------------------------------------------- 1 | # 作业:暂停和恢复爬行 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 有时,对于大型网站,暂停爬行并稍后恢复爬行是可取的。 6 | 7 | Scrapy通过提供以下功能来支持此功能: 8 | 9 | * 在磁盘上保持预定请求的计划程序 10 | * 重复的筛选器,用于将访问的请求保持在磁盘上 11 | * 在批处理之间保持某些 Spider 状态(键/值对)持久的扩展。 12 | 13 | ## 作业目录 14 | 15 | 要启用持久性支持,只需定义 _job directory_ 通过 `JOBDIR` 设置。这个目录将用于存储保持单个作业(即 Spider 运行)状态所需的所有数据。需要注意的是,这个目录不能由不同的 Spider 共享,甚至不能由同一 Spider 的不同作业/运行共享,因为它用于存储 _single_ 工作。 16 | 17 | ## 如何使用它 18 | 19 | 要在启用持久性支持的情况下启动spider,请按如下方式运行: 20 | 21 | ```py 22 | scrapy crawl somespider -s JOBDIR=crawls/somespider-1 23 | 24 | ``` 25 | 26 | 然后,您可以随时安全地停止 Spider (通过按ctrl-c或发送信号),然后通过发出相同的命令恢复 Spider : 27 | 28 | ```py 29 | scrapy crawl somespider -s JOBDIR=crawls/somespider-1 30 | 31 | ``` 32 | 33 | ## 保持批之间的持久状态 34 | 35 | 有时您需要在暂停/恢复批处理之间保持一些持久的 Spider 状态。你可以使用 `spider.state` 属性,它应该是dict。当spider启动和停止时,有一个内置扩展负责从作业目录序列化、存储和加载该属性。 36 | 37 | 下面是一个使用spider状态的回调示例(为了简洁起见,省略了其他spider代码): 38 | 39 | ```py 40 | def parse_item(self, response): 41 | # parse item here 42 | self.state['items_count'] = self.state.get('items_count', 0) + 1 43 | 44 | ``` 45 | 46 | ## 持久性问题 47 | 48 | 如果您想使用零碎的持久性支持,需要记住以下几点: 49 | 50 | ### cookies过期 51 | 52 | cookies可能会过期。因此,如果您不快速恢复您的 Spider ,那么计划的请求可能不再有效。如果 Spider 不依赖饼干,这就不是问题了。 53 | 54 | ### 请求序列化 55 | 56 | 请求必须可由 `pickle` 模块,以便持久性工作,所以您应该确保您的请求是可序列化的。 57 | 58 | 这里最常见的问题是使用 `lambda` 无法持久化的请求回调函数。 59 | 60 | 例如,这不起作用: 61 | 62 | ```py 63 | def some_callback(self, response): 64 | somearg = 'test' 65 | return scrapy.Request('http://www.example.com', callback=lambda r: self.other_callback(r, somearg)) 66 | 67 | def other_callback(self, response, somearg): 68 | print("the argument passed is: %s" % somearg) 69 | 70 | ``` 71 | 72 | 但这将: 73 | 74 | ```py 75 | def some_callback(self, response): 76 | somearg = 'test' 77 | return scrapy.Request('http://www.example.com', callback=self.other_callback, meta={'somearg': somearg}) 78 | 79 | def other_callback(self, response): 80 | somearg = response.meta['somearg'] 81 | print("the argument passed is: %s" % somearg) 82 | 83 | ``` 84 | 85 | 如果要记录无法序列化的请求,可以设置 [`SCHEDULER_DEBUG`](settings.html#std:setting-SCHEDULER_DEBUG) 设置为 `True` 在项目的“设置”页中。它是 `False` 默认情况下。 -------------------------------------------------------------------------------- /docs/39.md: -------------------------------------------------------------------------------- 1 | # 延伸 Scrapy 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/4.md: -------------------------------------------------------------------------------- 1 | # 安装指南 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | ## 安装 Scrapy 6 | 7 | scrapy在cpython(默认的Python实现)和pypypy(从pypy 5.9开始)下运行于python 2.7和python 3.4或更高版本。 8 | 9 | 如果你在用 [Anaconda](https://docs.anaconda.com/anaconda/) 或 [Miniconda](https://conda.io/docs/user-guide/install/index.html) ,您可以从 [conda-forge](https://conda-forge.org/) 频道,它有最新的Linux、Windows和OS X软件包。 10 | 11 | 使用安装 Scrapy `conda` 运行: 12 | 13 | ```py 14 | conda install -c conda-forge scrapy 15 | 16 | ``` 17 | 18 | 或者,如果您已经熟悉了python包的安装,那么可以从pypi安装scrappy及其依赖项,方法是: 19 | 20 | ```py 21 | pip install Scrapy 22 | 23 | ``` 24 | 25 | 请注意,有时这可能需要根据操作系统解决一些零碎依赖项的编译问题,因此请确保检查 [平台特定安装说明](#intro-install-platform-notes) . 26 | 27 | 我们强烈建议您在 [a dedicated virtualenv](#intro-using-virtualenv) ,以避免与系统包冲突。 28 | 29 | 有关更详细和平台特定的说明以及故障排除信息,请阅读。 30 | 31 | ### 很好知道的事情 32 | 33 | scrappy是用纯python编写的,它依赖于几个关键的python包(以及其他包): 34 | 35 | * [lxml](http://lxml.de/) 一个高效的XML和HTML解析器 36 | * [parsel](https://pypi.python.org/pypi/parsel) ,一个写在lxml上面的html/xml数据提取库, 37 | * [w3lib](https://pypi.python.org/pypi/w3lib) ,用于处理URL和网页编码的多用途帮助程序 38 | * [twisted](https://twistedmatrix.com/) 异步网络框架 39 | * [cryptography](https://cryptography.io/) 和 [pyOpenSSL](https://pypi.python.org/pypi/pyOpenSSL) ,处理各种网络级安全需求 40 | 41 | Scrapy测试的最小版本是: 42 | 43 | * 扭曲14 44 | * LXML 3.4 45 | * PyopSnSL 0.14 46 | 47 | Scrapy可以与这些软件包的旧版本一起工作,但不能保证它会继续工作,因为它没有针对它们进行测试。 48 | 49 | 其中一些软件包本身依赖于非python软件包,这些软件包可能需要依赖于您的平台的其他安装步骤。请检查 [platform-specific guides below](#intro-install-platform-notes) . 50 | 51 | 如果与这些依赖项相关的任何问题,请参阅它们各自的安装说明: 52 | 53 | * [lxml installation](http://lxml.de/installation.html) 54 | * [cryptography installation](https://cryptography.io/en/latest/installation/) 55 | 56 | ### 使用虚拟环境(推荐) 57 | 58 | tl;dr:我们建议在所有平台上的虚拟环境中安装scrapy。 59 | 60 | python包可以在全局(也就是系统范围)或用户空间中安装。我们不建议在系统范围内安装Scrapy。 61 | 62 | 相反,我们建议您在所谓的“虚拟环境”中安装Scrapy。( [virtualenv](https://virtualenv.pypa.io) )virtualenvs允许您不与已经安装的python系统包冲突(这可能会破坏某些系统工具和脚本),并且仍然可以使用 `pip` (没有) `sudo` 诸如此类。 63 | 64 | 要开始使用虚拟环境,请参见 [virtualenv installation instructions](https://virtualenv.pypa.io/en/stable/installation/) . 要在全球范围内安装它(让它在全球范围内安装实际上有助于实现这一点),应该运行: 65 | 66 | ```py 67 | $ [sudo] pip install virtualenv 68 | 69 | ``` 70 | 71 | 检查这个 [user guide](https://virtualenv.pypa.io/en/stable/userguide/) 关于如何创建virtualenv。 72 | 73 | 注解 74 | 75 | 如果您使用Linux或OS X, [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/install.html) 是创建virtualenv的便利工具。 76 | 77 | 创建virtualenv后,可以在其中安装scrapy `pip` 就像其他的python包一样。(见 [platform-specific guides](#intro-install-platform-notes) 下面是您可能需要预先安装的非python依赖项)。 78 | 79 | 默认情况下,可以创建python virtualenv来使用python 2或python 3。 80 | 81 | * 如果要使用python 3安装scrapy,请在python 3 virtualenv中安装scrapy。 82 | * 如果您想用python 2安装scrapy,请在python 2 virtualenv中安装scrapy。 83 | 84 | ## 平台特定安装说明 85 | 86 | ### Windows 87 | 88 | 虽然可以使用pip在Windows上安装scrapy,但我们建议您安装 [Anaconda](https://docs.anaconda.com/anaconda/) 或 [Miniconda](https://conda.io/docs/user-guide/install/index.html) 并使用来自 [conda-forge](https://conda-forge.org/) 这样可以避免大多数安装问题。 89 | 90 | 安装后 [Anaconda](https://docs.anaconda.com/anaconda/) 或 [Miniconda](https://conda.io/docs/user-guide/install/index.html) ,安装 Scrapy : 91 | 92 | ```py 93 | conda install -c conda-forge scrapy 94 | 95 | ``` 96 | 97 | ### Ubuntu 14.04或以上 98 | 99 | Scrapy目前已经用LXML、Twisted和PyOpenSSL的最新版本进行了测试,并且与最新的Ubuntu发行版兼容。但是它也应该支持Ubuntu的旧版本,比如Ubuntu14.04,尽管存在与TLS连接相关的潜在问题。 100 | 101 | **Don't** 使用 `python-scrapy` Ubuntu提供的软件包,它们通常太旧,速度太慢,赶不上最新的垃圾。 102 | 103 | 要在Ubuntu(或基于Ubuntu的)系统上安装Scrapy,需要安装以下依赖项: 104 | 105 | ```py 106 | sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev 107 | 108 | ``` 109 | 110 | * `python-dev`, `zlib1g-dev`, `libxml2-dev` and `libxslt1-dev` are required for `lxml` 111 | * `libssl-dev` and `libffi-dev` are required for `cryptography` 112 | 113 | 如果要在python 3上安装scrapy,还需要python 3开发头: 114 | 115 | ```py 116 | sudo apt-get install python3 python3-dev 117 | 118 | ``` 119 | 120 | 里面 [virtualenv](#intro-using-virtualenv) ,您可以安装Scrapy `pip` 之后:: 121 | 122 | ```py 123 | pip install scrapy 124 | 125 | ``` 126 | 127 | 注解 128 | 129 | 相同的非python依赖项可用于在debian jessie(8.0)及更高版本中安装scrapy。 130 | 131 | ### Mac OS X 132 | 133 | 构建Scrapy的依赖项需要有一个C编译器和开发头。在OS X上,这通常由苹果的Xcode开发工具提供。要安装xcode命令行工具,请打开终端窗口并运行: 134 | 135 | ```py 136 | xcode-select --install 137 | 138 | ``` 139 | 140 | 有一个 [known issue](https://github.com/pypa/pip/issues/2468) 防止 `pip` 更新系统包。必须解决此问题才能成功安装Scrapy及其依赖项。以下是一些建议的解决方案: 141 | 142 | * _(推荐)_ **Don't** 使用系统python,安装一个新的、更新的版本,它不会与系统的其他部分冲突。以下是如何使用 [homebrew](https://brew.sh/) 包管理器: 143 | 144 | * 安装 [homebrew](https://brew.sh/) 遵循https://brew.sh中的说明/ 145 | 146 | * 更新你的 `PATH` 变量,说明应在系统包之前使用自制包(更改 `.bashrc` 到 `.zshrc` 如果你在使用 [zsh](https://www.zsh.org/) 作为默认Shell):: 147 | 148 | ```py 149 | echo "export PATH=/usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc 150 | 151 | ``` 152 | 153 | * 再装填 `.bashrc` 为确保变更发生: 154 | 155 | ```py 156 | source ~/.bashrc 157 | 158 | ``` 159 | 160 | * 安装python:: 161 | 162 | ```py 163 | brew install python 164 | 165 | ``` 166 | 167 | * 最新版本的python `pip` 与它们捆绑在一起,这样您就不需要单独安装。如果不是这样,请升级python:: 168 | 169 | ```py 170 | brew update; brew upgrade python 171 | 172 | ``` 173 | 174 | * [*](#id1)(可选)*在隔离的python环境中安装scrapy。 175 | 176 | 此方法是解决上述OS X问题的一种方法,但它是管理依赖性的总体良好实践,可以补充第一种方法。 177 | 178 | [virtualenv](https://virtualenv.pypa.io) 是一个可以用来在Python中创建虚拟环境的工具。我们建议阅读http://docs.python-guide.org/en/latest/dev/virtualenvs/这样的教程开始学习。 179 | 180 | 在任何这些解决方法之后,您都应该能够安装scrapy:: 181 | 182 | ```py 183 | pip install Scrapy 184 | 185 | ``` 186 | 187 | ### PyPy 188 | 189 | 我们建议使用最新的Pypy版本。测试版本为5.9.0。对于pypy3,只测试了Linux安装。 190 | 191 | 大多数依赖于废品的人现在都有cpython的二进制轮子,而不是pypy的。这意味着这些依赖项将在安装期间构建。在OSX上,您可能会面临构建加密依赖关系的问题,本文描述了该问题的解决方案。 [here](https://github.com/pyca/cryptography/issues/2692#issuecomment-272773481) ,就是 `brew install openssl` 然后导出此命令推荐的标志(仅在安装scrapy时需要)。在Linux上安装除了安装构建依赖项之外没有任何特殊问题。未测试在Windows上安装带有Pypy的Scrapy。 192 | 193 | 您可以通过运行来检查Scrapy是否安装正确。 `scrapy bench` . 如果此命令给出错误,例如 `TypeError: ... got 2 unexpected keyword arguments` ,这意味着安装工具无法获取一个Pypy特定的依赖项。要解决此问题,请运行 `pip install 'PyPyDispatcher>=2.1.0'` . 194 | 195 | ## 故障排除 196 | 197 | ### attributeError:“module”对象没有属性“op u no u tlsv1 u 1” 198 | 199 | 安装或升级scrappy、twisted或pyopenssl之后,可能会得到以下跟踪的异常: 200 | 201 | ```py 202 | […] 203 | File "[…]/site-packages/twisted/protocols/tls.py", line 63, in 204 | from twisted.internet._sslverify import _setAcceptableProtocols 205 | File "[…]/site-packages/twisted/internet/_sslverify.py", line 38, in 206 | TLSVersion.TLSv1_1: SSL.OP_NO_TLSv1_1, 207 | AttributeError: 'module' object has no attribute 'OP_NO_TLSv1_1' 208 | 209 | ``` 210 | 211 | 您得到这个异常的原因是您的系统或虚拟环境有一个您的Twisted版本不支持的pyopenssl版本。 212 | 213 | 要安装您的Twisted版本支持的pyopenssl版本,请使用 `tls` 额外选项: 214 | 215 | ```py 216 | pip install twisted[tls] 217 | 218 | ``` 219 | 220 | 有关详细信息,请参阅 [Issue #2473](https://github.com/scrapy/scrapy/issues/2473) . -------------------------------------------------------------------------------- /docs/40.md: -------------------------------------------------------------------------------- 1 | # 体系结构概述 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 本文描述了Scrapy的体系结构及其组件如何交互。 6 | 7 | ## 概述 8 | 9 | 下图显示了Scrapy架构及其组件的概述,以及系统内部发生的数据流的概要(以红色箭头显示)。下面提供了这些组件的简要说明以及有关它们的详细信息的链接。数据流也描述如下。 10 | 11 | ## 数据流 12 | 13 | [![Scrapy architecture](img/d74a68f3540ed16e6533632095e18fc1.jpg)](../_images/scrapy_architecture_02.png) 14 | 15 | Scrapy中的数据流由执行引擎控制,如下所示: 16 | 17 | 1. 这个 [Engine](#component-engine) 获取要从 [Spider](#component-spiders) . 18 | 2. 这个 [Engine](#component-engine) 在中安排请求 [Scheduler](#component-scheduler) 并请求下一个要爬行的请求。 19 | 3. 这个 [Scheduler](#component-scheduler) 将下一个请求返回到 [Engine](#component-engine) . 20 | 4. 这个 [Engine](#component-engine) 将请求发送到 [Downloader](#component-downloader) ,通过 [Downloader Middlewares](#component-downloader-middleware) (见 [`process_request()`](downloader-middleware.html#scrapy.downloadermiddlewares.DownloaderMiddleware.process_request "scrapy.downloadermiddlewares.DownloaderMiddleware.process_request") ) 21 | 5. 一旦页面完成下载, [Downloader](#component-downloader) 生成响应(使用该页)并将其发送到引擎,并通过 [Downloader Middlewares](#component-downloader-middleware) (见 [`process_response()`](downloader-middleware.html#scrapy.downloadermiddlewares.DownloaderMiddleware.process_response "scrapy.downloadermiddlewares.DownloaderMiddleware.process_response") ) 22 | 6. 这个 [Engine](#component-engine) 接收来自的响应 [Downloader](#component-downloader) 并发送到 [Spider](#component-spiders) 用于处理,通过 [Spider Middleware](#component-spider-middleware) (见 [`process_spider_input()`](spider-middleware.html#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input") ) 23 | 7. 这个 [Spider](#component-spiders) 处理响应并向 [Engine](#component-engine) ,通过 [Spider Middleware](#component-spider-middleware) (见 [`process_spider_output()`](spider-middleware.html#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") ) 24 | 8. 这个 [Engine](#component-engine) 将已处理的项目发送到 [Item Pipelines](#component-pipelines) ,然后将已处理的请求发送到 [Scheduler](#component-scheduler) 并请求可能的下一个爬行请求。 25 | 9. 该过程重复(从步骤1开始),直到不再有来自 [Scheduler](#component-scheduler) . 26 | 27 | ## 组件 28 | 29 | ### 抓取式发动机 30 | 31 | 引擎负责控制系统所有组件之间的数据流,并在发生某些操作时触发事件。见 [Data Flow](#data-flow) 有关详细信息,请参阅上面的部分。 32 | 33 | ### 调度程序 34 | 35 | 调度器接收来自引擎的请求,并将它们排队,以便在引擎请求时(也向引擎)提供这些请求。 36 | 37 | ### 下载器 38 | 39 | 下载者负责获取网页并将其送入引擎,引擎反过来又将网页送入 Spider 。 40 | 41 | ### Spider 42 | 43 | spider是由scraphy用户编写的自定义类,用于解析响应并从中提取项目(也称为scraped项)或后续的附加请求。有关详细信息,请参阅 [Spider](spiders.html#topics-spiders) . 44 | 45 | ### 项目管道 46 | 47 | 项目管道负责处理被 Spider 提取(或 Scrape)的项目。典型的任务包括清理、验证和持久性(如将项目存储在数据库中)。有关详细信息,请参阅 [项目管道](item-pipeline.html#topics-item-pipeline) . 48 | 49 | ### 下载器中心件 50 | 51 | 下载器中间件是位于引擎和下载器之间的特定Hook,当它们从引擎传递到下载器时处理请求,以及从下载器传递到引擎的响应。 52 | 53 | 如果需要执行以下操作之一,请使用下载器中间件: 54 | 55 | * 在将请求发送给下载者之前处理该请求(即在Scrapy将请求发送到网站之前); 56 | * 变更在传递给spider之前收到响应; 57 | * 发送新的请求,而不是将收到的响应传递给spider; 58 | * 在不获取网页的情况下将响应传递给 Spider ; 59 | * 悄悄地放弃一些请求。 60 | 61 | 有关详细信息,请参阅 [下载器中间件](downloader-middleware.html#topics-downloader-middleware) . 62 | 63 | ### Spider 中心件 64 | 65 | Spider 中间件是位于引擎和 Spider 之间的特定Hook,能够处理 Spider 的输入(响应)和输出(项目和请求)。 66 | 67 | 如果需要,使用 Spider 中间件 68 | 69 | * post-process output of spider callbacks - change/add/remove requests or items; 70 | * 后处理启动请求; 71 | * 处理spider异常; 72 | * 对一些基于响应内容的请求调用errback,而不是回调。 73 | 74 | 有关详细信息,请参阅 [Spider 中间件](spider-middleware.html#topics-spider-middleware) . 75 | 76 | ## 事件驱动的网络 77 | 78 | Scrapy是用 [Twisted](https://twistedmatrix.com/trac/) 是一个流行的事件驱动的python网络框架。因此,它使用非阻塞(即异步)代码实现并发性。 79 | 80 | 有关异步编程和扭曲的更多信息,请参阅以下链接: 81 | 82 | * [Introduction to Deferreds in Twisted](https://twistedmatrix.com/documents/current/core/howto/defer-intro.html) 83 | * [Twisted - hello, asynchronous programming](http://jessenoller.com/blog/2009/02/11/twisted-hello-asynchronous-programming/) 84 | * [Twisted Introduction - Krondo](http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/) -------------------------------------------------------------------------------- /docs/43.md: -------------------------------------------------------------------------------- 1 | # 扩展 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 扩展框架提供了一种将您自己的自定义功能插入到Scrapy中的机制。 6 | 7 | 扩展只是在初始化扩展时,在scrapy启动时实例化的常规类。 8 | 9 | ## 扩展设置 10 | 11 | 扩展使用 [Scrapy settings](settings.html#topics-settings) 管理他们的设置,就像任何其他零碎的代码一样。 12 | 13 | 扩展通常会在其设置前面加上自己的名称,以避免与现有(和将来)扩展冲突。例如,要处理的假设扩展 [Google Sitemaps](https://en.wikipedia.org/wiki/Sitemaps) 将使用如下设置 `GOOGLESITEMAP_ENABLED` , `GOOGLESITEMAP_DEPTH` 等等。 14 | 15 | ## 加载和激活扩展 16 | 17 | 通过实例化扩展类的单个实例,可以在启动时加载和激活扩展。因此,所有扩展初始化代码都必须在类构造函数中执行。( `__init__` 方法)。 18 | 19 | 若要使扩展名可用,请将其添加到 [`EXTENSIONS`](settings.html#std:setting-EXTENSIONS) 设置你的剪贴设置。在 [`EXTENSIONS`](settings.html#std:setting-EXTENSIONS) ,每个扩展都由一个字符串表示:扩展类名的完整python路径。例如:: 20 | 21 | ```py 22 | EXTENSIONS = { 23 | 'scrapy.extensions.corestats.CoreStats': 500, 24 | 'scrapy.extensions.telnet.TelnetConsole': 500, 25 | } 26 | 27 | ``` 28 | 29 | 如你所见, [`EXTENSIONS`](settings.html#std:setting-EXTENSIONS) 设置是一个dict,其中键是扩展路径,它们的值是定义扩展的顺序。 _loading_ 秩序。这个 [`EXTENSIONS`](settings.html#std:setting-EXTENSIONS) 设置与合并 [`EXTENSIONS_BASE`](settings.html#std:setting-EXTENSIONS_BASE) 在scrappy中定义的设置(不打算被重写),然后按顺序排序,以获得已启用扩展的最终排序列表。 30 | 31 | 由于扩展通常不相互依赖,因此在大多数情况下,它们的加载顺序是不相关的。这就是为什么 [`EXTENSIONS_BASE`](settings.html#std:setting-EXTENSIONS_BASE) 设置以相同的顺序定义所有扩展( `0` )但是,如果需要添加依赖于已加载的其他扩展的扩展,则可以利用此功能。 32 | 33 | ## 可用、启用和禁用扩展 34 | 35 | 并非所有可用的扩展都将启用。其中一些通常取决于特定的设置。例如,HTTP缓存扩展在默认情况下是可用的,但在 [`HTTPCACHE_ENABLED`](downloader-middleware.html#std:setting-HTTPCACHE_ENABLED) 设置设置。 36 | 37 | ## 禁用扩展 38 | 39 | 为了禁用默认启用的扩展(即包含在 [`EXTENSIONS_BASE`](settings.html#std:setting-EXTENSIONS_BASE) 设置)必须将其顺序设置为 `None` . 例如:: 40 | 41 | ```py 42 | EXTENSIONS = { 43 | 'scrapy.extensions.corestats.CoreStats': None, 44 | } 45 | 46 | ``` 47 | 48 | ## 编写自己的扩展名 49 | 50 | 每个扩展都是一个Python类。 Scrapy 扩展(也包括中间产品和管道)的主要入口点是 `from_crawler` 类方法,它接收 `Crawler` 实例。通过爬虫对象,您可以访问设置、信号、统计信息,还可以控制爬行行为。 51 | 52 | 通常,扩展连接到 [signals](signals.html#topics-signals) 并执行由它们触发的任务。 53 | 54 | 最后,如果 `from_crawler` 方法引发 [`NotConfigured`](exceptions.html#scrapy.exceptions.NotConfigured "scrapy.exceptions.NotConfigured") 异常,扩展将被禁用。否则,将启用扩展。 55 | 56 | ### 样本扩展 57 | 58 | 在这里,我们将实现一个简单的扩展来说明前一节中描述的概念。此扩展将每次记录一条消息: 59 | 60 | * Spider 被打开了 61 | * Spider 被关闭了 62 | * 特定数量的物品被刮掉 63 | 64 | 扩展将通过 `MYEXT_ENABLED` 设置和项目数将通过 `MYEXT_ITEMCOUNT` 设置。 65 | 66 | 这是这种扩展的代码: 67 | 68 | ```py 69 | import logging 70 | from scrapy import signals 71 | from scrapy.exceptions import NotConfigured 72 | 73 | logger = logging.getLogger(__name__) 74 | 75 | class SpiderOpenCloseLogging(object): 76 | 77 | def __init__(self, item_count): 78 | self.item_count = item_count 79 | self.items_scraped = 0 80 | 81 | @classmethod 82 | def from_crawler(cls, crawler): 83 | # first check if the extension should be enabled and raise 84 | # NotConfigured otherwise 85 | if not crawler.settings.getbool('MYEXT_ENABLED'): 86 | raise NotConfigured 87 | 88 | # get the number of items from settings 89 | item_count = crawler.settings.getint('MYEXT_ITEMCOUNT', 1000) 90 | 91 | # instantiate the extension object 92 | ext = cls(item_count) 93 | 94 | # connect the extension object to signals 95 | crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) 96 | crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) 97 | crawler.signals.connect(ext.item_scraped, signal=signals.item_scraped) 98 | 99 | # return the extension object 100 | return ext 101 | 102 | def spider_opened(self, spider): 103 | logger.info("opened spider %s", spider.name) 104 | 105 | def spider_closed(self, spider): 106 | logger.info("closed spider %s", spider.name) 107 | 108 | def item_scraped(self, item, spider): 109 | self.items_scraped += 1 110 | if self.items_scraped % self.item_count == 0: 111 | logger.info("scraped %d items", self.items_scraped) 112 | 113 | ``` 114 | 115 | ## 内置扩展引用 116 | 117 | ### 通用扩展 118 | 119 | #### 日志统计扩展 120 | 121 | ```py 122 | class scrapy.extensions.logstats.LogStats 123 | ``` 124 | 125 | 记录基本的统计信息,如已爬网的页面和已擦除的项目。 126 | 127 | #### 核心统计扩展 128 | 129 | ```py 130 | class scrapy.extensions.corestats.CoreStats 131 | ``` 132 | 133 | 启用核心统计信息集合,前提是已启用统计信息集合(请参见 [统计数据集合](stats.html#topics-stats) ) 134 | 135 | #### Telnet控制台扩展 136 | 137 | ```py 138 | class scrapy.extensions.telnet.TelnetConsole 139 | ``` 140 | 141 | 提供一个telnet控制台,用于进入当前运行的scrapy进程中的python解释器,这对于调试非常有用。 142 | 143 | telnet控制台必须由 [`TELNETCONSOLE_ENABLED`](settings.html#std:setting-TELNETCONSOLE_ENABLED) 设置,服务器将侦听中指定的端口 [`TELNETCONSOLE_PORT`](telnetconsole.html#std:setting-TELNETCONSOLE_PORT) . 144 | 145 | #### 内存使用扩展 146 | 147 | ```py 148 | class scrapy.extensions.memusage.MemoryUsage 149 | ``` 150 | 151 | 注解 152 | 153 | 此扩展在Windows中不起作用。 154 | 155 | 监视运行spider的scrapy进程使用的内存,并: 156 | 157 | 1. 超过某个值时发送通知电子邮件 158 | 2. 当 Spider 超过某个值时关闭 Spider 159 | 160 | 当达到某个警告值时,可以触发通知电子邮件。( [`MEMUSAGE_WARNING_MB`](settings.html#std:setting-MEMUSAGE_WARNING_MB) )当达到最大值时( [`MEMUSAGE_LIMIT_MB`](settings.html#std:setting-MEMUSAGE_LIMIT_MB) )这也会导致 Spider 被关闭, Scrapy 过程被终止。 161 | 162 | 此扩展由 [`MEMUSAGE_ENABLED`](settings.html#std:setting-MEMUSAGE_ENABLED) 设置,可以使用以下设置进行配置: 163 | 164 | * [`MEMUSAGE_LIMIT_MB`](settings.html#std:setting-MEMUSAGE_LIMIT_MB) 165 | * [`MEMUSAGE_WARNING_MB`](settings.html#std:setting-MEMUSAGE_WARNING_MB) 166 | * [`MEMUSAGE_NOTIFY_MAIL`](settings.html#std:setting-MEMUSAGE_NOTIFY_MAIL) 167 | * [`MEMUSAGE_CHECK_INTERVAL_SECONDS`](settings.html#std:setting-MEMUSAGE_CHECK_INTERVAL_SECONDS) 168 | 169 | #### 内存调试器扩展 170 | 171 | ```py 172 | class scrapy.extensions.memdebug.MemoryDebugger 173 | ``` 174 | 175 | 调试内存使用情况的扩展。它收集以下信息: 176 | 177 | * python垃圾收集器未收集的对象 178 | * 不应该保留的对象。有关详细信息,请参阅 [使用调试内存泄漏 trackref](leaks.html#topics-leaks-trackrefs) 179 | 180 | 要启用此扩展,请打开 [`MEMDEBUG_ENABLED`](settings.html#std:setting-MEMDEBUG_ENABLED) 设置。信息将存储在统计信息中。 181 | 182 | #### 关闭星形延长件 183 | 184 | ```py 185 | class scrapy.extensions.closespider.CloseSpider 186 | ``` 187 | 188 | 当满足某些条件时,使用每个条件的特定关闭原因自动关闭 Spider 。 189 | 190 | 关闭 Spider 的条件可以通过以下设置进行配置: 191 | 192 | * [`CLOSESPIDER_TIMEOUT`](#std:setting-CLOSESPIDER_TIMEOUT) 193 | * [`CLOSESPIDER_ITEMCOUNT`](#std:setting-CLOSESPIDER_ITEMCOUNT) 194 | * [`CLOSESPIDER_PAGECOUNT`](#std:setting-CLOSESPIDER_PAGECOUNT) 195 | * [`CLOSESPIDER_ERRORCOUNT`](#std:setting-CLOSESPIDER_ERRORCOUNT) 196 | 197 | ##### CLOSESPIDER_TIMEOUT 198 | 199 | 违约: `0` 200 | 201 | 指定秒数的整数。如果 Spider 保持打开超过该秒数,它将自动关闭,原因如下 `closespider_timeout` . 如果为零(或未设置), Spider 将不会在超时时关闭。 202 | 203 | ##### CLOSESPIDER_ITEMCOUNT 204 | 205 | 违约: `0` 206 | 207 | 指定若干项的整数。如果spider的抓取量超过该数量,并且这些项目通过项目管道,那么spider将关闭,原因是 `closespider_itemcount` . 当前在下载器队列中的请求(最多 [`CONCURRENT_REQUESTS`](settings.html#std:setting-CONCURRENT_REQUESTS) 请求)仍在处理中。如果为零(或未设置), Spider 将不会被通过的项目数关闭。 208 | 209 | ##### CLOSESPIDER_PAGECOUNT 210 | 211 | 0.11 新版功能. 212 | 213 | 违约: `0` 214 | 215 | 指定要爬网的最大响应数的整数。如果 Spider 爬得比这个还多, Spider 会被关闭的,原因是 `closespider_pagecount` . 如果为零(或未设置), Spider 将不会被爬行响应的数量关闭。 216 | 217 | ##### CLOSESPIDER_ERRORCOUNT 218 | 219 | 0.11 新版功能. 220 | 221 | 违约: `0` 222 | 223 | 一个整数,指定关闭 Spider 之前要接收的最大错误数。如果spider生成的错误数量超过该数量,则会关闭它并说明原因。 `closespider_errorcount` . 如果为零(或未设置), Spider 将不会被错误数关闭。 224 | 225 | #### StatsMailer扩展 226 | 227 | ```py 228 | class scrapy.extensions.statsmailer.StatsMailer 229 | ``` 230 | 231 | 这个简单的扩展可用于在域完成抓取时发送通知电子邮件,包括收集到的残缺统计信息。电子邮件将发送给 [`STATSMAILER_RCPTS`](settings.html#std:setting-STATSMAILER_RCPTS) 设置。 232 | 233 | ### 调试扩展 234 | 235 | #### 堆栈跟踪转储扩展 236 | 237 | ```py 238 | class scrapy.extensions.debug.StackTraceDump 239 | ``` 240 | 241 | 当 [SIGQUIT](https://en.wikipedia.org/wiki/SIGQUIT) 或 [SIGUSR2](https://en.wikipedia.org/wiki/SIGUSR1_and_SIGUSR2) 接收到信号。转储的信息如下: 242 | 243 | 1. 发动机状态(使用 `scrapy.utils.engine.get_engine_status()` ) 244 | 2. 实时参考(请参见 [使用调试内存泄漏 trackref](leaks.html#topics-leaks-trackrefs) ) 245 | 3. 所有线程的堆栈跟踪 246 | 247 | 在转储堆栈跟踪和引擎状态后,碎片进程继续正常运行。 248 | 249 | 此扩展仅在符合POSIX的平台(即,不是Windows)上工作,因为 [SIGQUIT](https://en.wikipedia.org/wiki/SIGQUIT) 和 [SIGUSR2](https://en.wikipedia.org/wiki/SIGUSR1_and_SIGUSR2) Windows上没有信号。 250 | 251 | 至少有两种方法可以将Scrapy [SIGQUIT](https://en.wikipedia.org/wiki/SIGQUIT) 信号: 252 | 253 | 1. 按ctrl-while a scrapy process is running(Linux only?) 254 | 255 | 2. 通过运行此命令(假设 `<pid>` 是 Scrapy 流程的流程ID):: 256 | 257 | ```py 258 | kill -QUIT <pid> 259 | 260 | ``` 261 | 262 | #### 调试器扩展 263 | 264 | ```py 265 | class scrapy.extensions.debug.Debugger 266 | ``` 267 | 268 | 调用一个 [Python debugger](https://docs.python.org/2/library/pdb.html) 当 [SIGUSR2](https://en.wikipedia.org/wiki/SIGUSR1_and_SIGUSR2) 接收到信号。退出调试程序后,碎片处理程序继续正常运行。 269 | 270 | 有关详细信息,请参阅 [Debugging in Python](https://pythonconquerstheuniverse.wordpress.com/2009/09/10/debugging-in-python/) . 271 | 272 | 此扩展仅在符合POSIX的平台(即,不是Windows)上工作。 -------------------------------------------------------------------------------- /docs/44.md: -------------------------------------------------------------------------------- 1 | # 核心API 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 0.15 新版功能. 6 | 7 | 本节记录了Scrapy核心API,它是为扩展和中间件的开发人员设计的。 8 | 9 | ## 爬虫API 10 | 11 | Scrapy API的主要入口点是 [`Crawler`](#scrapy.crawler.Crawler "scrapy.crawler.Crawler") 对象,通过 `from_crawler` 类方法。这个对象提供对所有Scrapy核心组件的访问,它是扩展访问它们并将其功能连接到Scrapy的唯一方法。 12 | 13 | 扩展管理器负责加载和跟踪已安装的扩展,并通过 [`EXTENSIONS`](settings.html#std:setting-EXTENSIONS) 包含所有可用扩展名及其顺序的字典的设置,类似于 [configure the downloader middlewares](downloader-middleware.html#topics-downloader-middleware-setting) . 14 | 15 | ```py 16 | class scrapy.crawler.Crawler(spidercls, settings) 17 | ``` 18 | 19 | 爬虫对象必须用 [`scrapy.spiders.Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") 子类和A [`scrapy.settings.Settings`](#scrapy.settings.Settings "scrapy.settings.Settings") 对象。 20 | 21 | ```py 22 | settings 23 | ``` 24 | 25 | 此爬网程序的设置管理器。 26 | 27 | 这被扩展和中间软件用来访问这个爬虫程序的碎片设置。 28 | 29 | 有关 Scrapy 设置的介绍,请参见 [设置](settings.html#topics-settings) . 30 | 31 | 对于API见 [`Settings`](#scrapy.settings.Settings "scrapy.settings.Settings") 类。 32 | 33 | ```py 34 | signals 35 | ``` 36 | 37 | 这个爬虫的信号管理器。 38 | 39 | 这被扩展和中间商用来将自己连接到零碎的功能中。 40 | 41 | 有关信号的介绍,请参见 [信号](signals.html#topics-signals) . 42 | 43 | 对于API见 `SignalManager` 类。 44 | 45 | ```py 46 | stats 47 | ``` 48 | 49 | 这个爬虫的统计收集程序。 50 | 51 | 这用于从扩展和中间软件记录其行为的统计信息,或访问由其他扩展收集的统计信息。 52 | 53 | 有关stats集合的介绍,请参见 [统计数据集合](stats.html#topics-stats) . 54 | 55 | 对于API见 [`StatsCollector`](#scrapy.statscollectors.StatsCollector "scrapy.statscollectors.StatsCollector") 类。 56 | 57 | ```py 58 | extensions 59 | ``` 60 | 61 | 跟踪已启用扩展的扩展管理器。 62 | 63 | 大多数扩展不需要访问这个属性。 64 | 65 | 有关扩展名的介绍和scrapy上可用扩展名的列表,请参见 [扩展](extensions.html#topics-extensions) . 66 | 67 | ```py 68 | engine 69 | ``` 70 | 71 | 执行引擎,它协调调度程序、下载程序和spider之间的核心爬行逻辑。 72 | 73 | 有些扩展可能希望访问scrapy引擎,检查或修改下载程序和调度程序的行为,尽管这是一种高级用法,而且这个API还不稳定。 74 | 75 | ```py 76 | spider 77 | ``` 78 | 79 | Spider 当前正在被爬行。这是构建爬虫程序时提供的 Spider 类的实例,它是在 [`crawl()`](#scrapy.crawler.Crawler.crawl "scrapy.crawler.Crawler.crawl") 方法。 80 | 81 | ```py 82 | crawl(*args, **kwargs) 83 | ``` 84 | 85 | 通过用给定的 `args` 和 `kwargs` 参数,同时设置运行中的执行引擎。 86 | 87 | 返回在爬网完成时激发的延迟。 88 | 89 | ## 设置API 90 | 91 | ```py 92 | scrapy.settings.SETTINGS_PRIORITIES 93 | ``` 94 | 95 | 设置Scrapy中使用的默认设置优先级的键名称和优先级级别的字典。 96 | 97 | 每个项目定义一个设置入口点,为其提供标识代码名和整数优先级。在 [`Settings`](#scrapy.settings.Settings "scrapy.settings.Settings") 类。 98 | 99 | ```py 100 | SETTINGS_PRIORITIES = { 101 | 'default': 0, 102 | 'command': 10, 103 | 'project': 20, 104 | 'spider': 30, 105 | 'cmdline': 40, 106 | } 107 | 108 | ``` 109 | 110 | 有关每个设置源的详细说明,请参阅: [设置](settings.html#topics-settings) . 111 | 112 | ```py 113 | scrapy.settings.get_settings_priority(priority) 114 | ``` 115 | 116 | 在中查找给定字符串优先级的小助手函数 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") 并返回其数值,或直接返回给定的数值优先级。 117 | 118 | ```py 119 | class scrapy.settings.Settings(values=None, priority='project') 120 | ``` 121 | 122 | 基类:[`scrapy.settings.BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings") 123 | 124 | 此对象存储内部组件配置的碎片设置,并可用于任何进一步的自定义。 125 | 126 | 它是一个直接的子类,支持 [`BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings") . 另外,在实例化这个类之后,新对象将具有上面描述的全局默认设置 [内置设置参考](settings.html#topics-settings-ref) 已经填充。 127 | 128 | ```py 129 | class scrapy.settings.BaseSettings(values=None, priority='project') 130 | ``` 131 | 132 | 此类的实例的行为类似于字典,但将优先级与其 `(key, value)` 对,并且可以冻结(即标记为不可变)。 133 | 134 | 键值项可以在初始化时通过 `values` 他们会接受 `priority` 水平(除非 `values` 已经是的实例 [`BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings") 在这种情况下,将保留现有的优先级)。如果 `priority` 参数是字符串,优先级名称将在 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") . 否则,应提供特定的整数。 135 | 136 | 创建对象后,可以使用 [`set()`](#scrapy.settings.BaseSettings.set "scrapy.settings.BaseSettings.set") 方法,并且可以使用字典的方括号符号或 [`get()`](#scrapy.settings.BaseSettings.get "scrapy.settings.BaseSettings.get") 实例的方法及其值转换变量。请求存储的密钥时,将检索具有最高优先级的值。 137 | 138 | ```py 139 | copy() 140 | ``` 141 | 142 | 对当前设置进行深度复制。 143 | 144 | 此方法返回 [`Settings`](#scrapy.settings.Settings "scrapy.settings.Settings") 类,使用相同的值及其优先级填充。 145 | 146 | 对新对象的修改不会反映在原始设置上。 147 | 148 | ```py 149 | copy_to_dict() 150 | ``` 151 | 152 | 复制当前设置并转换为dict。 153 | 154 | 此方法返回一个新的dict,该dict使用与当前设置相同的值及其优先级填充。 155 | 156 | 对返回的dict的修改不会反映在原始设置上。 157 | 158 | 例如,此方法对于在Scrapy Shell中打印设置很有用。 159 | 160 | ```py 161 | freeze() 162 | ``` 163 | 164 | 禁用对当前设置的进一步更改。 165 | 166 | 调用此方法后,设置的当前状态将变为不可变。尝试通过 [`set()`](#scrapy.settings.BaseSettings.set "scrapy.settings.BaseSettings.set") 方法及其变体是不可能的,将被警告。 167 | 168 | ```py 169 | frozencopy() 170 | ``` 171 | 172 | 返回当前设置的不可变副本。 173 | 174 | A的别名 [`freeze()`](#scrapy.settings.BaseSettings.freeze "scrapy.settings.BaseSettings.freeze") 调用返回的对象 [`copy()`](#scrapy.settings.BaseSettings.copy "scrapy.settings.BaseSettings.copy") . 175 | 176 | ```py 177 | get(name, default=None) 178 | ``` 179 | 180 | 在不影响其原始类型的情况下获取设置值。 181 | 182 | | 参数: | 183 | 184 | * **name** (_string_) -- 设置名称 185 | * **default** (_any_) -- 如果找不到设置,则返回的值 186 | 187 | | 188 | | --- | --- | 189 | 190 | ```py 191 | getbool(name, default=False) 192 | ``` 193 | 194 | 获取设置值作为布尔值。 195 | 196 | `1` , `'1'` 是真的 `` and `` “真” `` return `` 对 [``](#id1), while `` 0 [``](#id3), `` “0” [``](#id5), `` 假 [``](#id7), `` “假” `` and `` 没有 `` return `` 假`。 197 | 198 | 例如,通过设置为的环境变量填充的设置 `'0'` 将返回 `False` 使用此方法时。 199 | 200 | | 参数: | 201 | 202 | * **name** (_string_) -- 设置名称 203 | * **default** (_any_) -- 如果找不到设置,则返回的值 204 | 205 | | 206 | | --- | --- | 207 | 208 | ```py 209 | getdict(name, default=None) 210 | ``` 211 | 212 | 获取一个设置值作为字典。如果设置原始类型为字典,则返回其副本。如果它是一个字符串,它将作为JSON字典进行计算。如果它是一个 [`BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings") 实例本身,它将被转换为一个字典,其中包含所有当前设置值,这些值将由返回 [`get()`](#scrapy.settings.BaseSettings.get "scrapy.settings.BaseSettings.get") 以及丢失有关优先级和可变性的所有信息。 213 | 214 | | 参数: | 215 | 216 | * **name** (_string_) -- 设置名称 217 | * **default** (_any_) -- 如果找不到设置,则返回的值 218 | 219 | | 220 | | --- | --- | 221 | 222 | ```py 223 | getfloat(name, default=0.0) 224 | ``` 225 | 226 | 以浮点形式获取设置值。 227 | 228 | | 参数: | 229 | 230 | * **name** (_string_) -- 设置名称 231 | * **default** (_any_) -- 如果找不到设置,则返回的值 232 | 233 | | 234 | | --- | --- | 235 | 236 | ```py 237 | getint(name, default=0) 238 | ``` 239 | 240 | 以int形式获取设置值。 241 | 242 | | 参数: | 243 | 244 | * **name** (_string_) -- 设置名称 245 | * **default** (_any_) -- 如果找不到设置,则返回的值 246 | 247 | | 248 | | --- | --- | 249 | 250 | ```py 251 | getlist(name, default=None) 252 | ``` 253 | 254 | 以列表形式获取设置值。如果设置的原始类型是列表,则将返回其副本。如果是一个字符串,它将被“,”拆分。 255 | 256 | 例如,通过设置为的环境变量填充的设置 `'one,two'` 使用此方法时将返回一个列表['one'、'two']。 257 | 258 | | 参数: | 259 | 260 | * **name** (_string_) -- 设置名称 261 | * **default** (_any_) -- 如果找不到设置,则返回的值 262 | 263 | | 264 | | --- | --- | 265 | 266 | ```py 267 | getpriority(name) 268 | ``` 269 | 270 | 返回设置的当前数字优先级值,或 `None` 如果给定 `name` 不存在。 271 | 272 | | 参数: | **name** (_string_) -- 设置名称 | 273 | | --- | --- | 274 | 275 | ```py 276 | getwithbase(name) 277 | ``` 278 | 279 | 获取类似字典的设置及其 <cite>_BASE</cite> 对应的。 280 | 281 | | 参数: | **name** (_string_) -- 类似字典的设置的名称 | 282 | | --- | --- | 283 | 284 | ```py 285 | maxpriority() 286 | ``` 287 | 288 | 返回所有设置中存在的最高优先级的数值,或返回 `default` 从 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") 如果没有存储设置。 289 | 290 | ```py 291 | set(name, value, priority='project') 292 | ``` 293 | 294 | 存储具有给定优先级的键/值属性。 295 | 296 | 应填充设置 _before_ 配置爬虫对象(通过 `configure()` 方法),否则它们不会有任何效果。 297 | 298 | | 参数: | 299 | 300 | * **name** (_string_) -- 设置名称 301 | * **value** (_any_) -- 要与设置关联的值 302 | * **priority** (_string_ _or_ _int_) -- 设置的优先级。应该是 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") 或整数 303 | 304 | | 305 | | --- | --- | 306 | 307 | ```py 308 | setmodule(module, priority='project') 309 | ``` 310 | 311 | 存储具有给定优先级的模块的设置。 312 | 313 | 这是一个调用 [`set()`](#scrapy.settings.BaseSettings.set "scrapy.settings.BaseSettings.set") 对于每个全局声明的大写变量 `module` 提供的 `priority` . 314 | 315 | | 参数: | 316 | 317 | * **module** (_module object_ _or_ _string_) -- 模块或模块路径 318 | * **priority** (_string_ _or_ _int_) -- 设置的优先级。应该是 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") 或整数 319 | 320 | | 321 | | --- | --- | 322 | 323 | ```py 324 | update(values, priority='project') 325 | ``` 326 | 327 | 存储具有给定优先级的键/值对。 328 | 329 | 这是一个调用 [`set()`](#scrapy.settings.BaseSettings.set "scrapy.settings.BaseSettings.set") 每一项 `values` 提供的 `priority` . 330 | 331 | 如果 `values` 是一个字符串,它被假定为JSON编码并被解析为一个dict `json.loads()` 第一。如果是 [`BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings") 例如,每个键的优先级将被使用,并且 `priority` 参数被忽略。这允许使用单个命令插入/更新具有不同优先级的设置。 332 | 333 | | 参数: | 334 | 335 | * **values** (dict or string or [`BaseSettings`](#scrapy.settings.BaseSettings "scrapy.settings.BaseSettings")) -- 设置名称和值 336 | * **priority** (_string_ _or_ _int_) -- 设置的优先级。应该是 [`SETTINGS_PRIORITIES`](#scrapy.settings.SETTINGS_PRIORITIES "scrapy.settings.SETTINGS_PRIORITIES") 或整数 337 | 338 | | 339 | | --- | --- | 340 | 341 | ## SpiderLoader API 342 | 343 | ```py 344 | class scrapy.loader.SpiderLoader 345 | ``` 346 | 347 | 这个类负责检索和处理整个项目中定义的 Spider 类。 348 | 349 | 通过在 [`SPIDER_LOADER_CLASS`](settings.html#std:setting-SPIDER_LOADER_CLASS) 项目设置。他们必须全面实施 `scrapy.interfaces.ISpiderLoader` 保证无误执行的接口。 350 | 351 | ```py 352 | from_settings(settings) 353 | ``` 354 | 355 | Scrapy使用该类方法创建该类的实例。它使用当前的项目设置调用,并加载在 [`SPIDER_MODULES`](settings.html#std:setting-SPIDER_MODULES) 设置。 356 | 357 | | 参数: | **settings** ([`Settings`](#scrapy.settings.Settings "scrapy.settings.Settings") instance) -- 项目设置 | 358 | | --- | --- | 359 | 360 | ```py 361 | load(spider_name) 362 | ``` 363 | 364 | 获取具有给定名称的 Spider 类。它将在先前加载的spider中查找具有名称的spider类 `spider_name` 如果找不到,将引发keyerror。 365 | 366 | | 参数: | **spider_name** (_str_) -- Spider 类名 | 367 | | --- | --- | 368 | 369 | ```py 370 | list() 371 | ``` 372 | 373 | 获取项目中可用 Spider 的名称。 374 | 375 | ```py 376 | find_by_request(request) 377 | ``` 378 | 379 | 列出能够处理给定请求的 Spider 的名称。将尝试将请求的URL与 Spider 的域相匹配。 380 | 381 | | 参数: | **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") instance) -- 查询请求 | 382 | | --- | --- | 383 | 384 | ## 信号API 385 | 386 | ## 统计收集器API 387 | 388 | 在 [`scrapy.statscollectors`](stats.html#module-scrapy.statscollectors "scrapy.statscollectors: Stats Collectors") 模块和它们都实现由 [`StatsCollector`](#scrapy.statscollectors.StatsCollector "scrapy.statscollectors.StatsCollector") 类(它们都从中继承)。 389 | 390 | ```py 391 | class scrapy.statscollectors.StatsCollector 392 | ``` 393 | 394 | ```py 395 | get_value(key, default=None) 396 | ``` 397 | 398 | 返回给定stats键的值,如果该键不存在,则返回默认值。 399 | 400 | ```py 401 | get_stats() 402 | ``` 403 | 404 | 以dict形式获取当前运行的spider的所有统计信息。 405 | 406 | ```py 407 | set_value(key, value) 408 | ``` 409 | 410 | 为给定的stats键设置给定值。 411 | 412 | ```py 413 | set_stats(stats) 414 | ``` 415 | 416 | 使用传入的dict重写当前状态 `stats` 争论。 417 | 418 | ```py 419 | inc_value(key, count=1, start=0) 420 | ``` 421 | 422 | 假定给定的起始值(未设置时),按给定的计数递增给定的stats键的值。 423 | 424 | ```py 425 | max_value(key, value) 426 | ``` 427 | 428 | 仅当同一个键的当前值小于值时,才为给定键设置给定值。如果给定键没有当前值,则始终设置该值。 429 | 430 | ```py 431 | min_value(key, value) 432 | ``` 433 | 434 | 仅当同一键的当前值大于值时,才为给定键设置给定值。如果给定键没有当前值,则始终设置该值。 435 | 436 | ```py 437 | clear_stats() 438 | ``` 439 | 440 | 清除所有统计。 441 | 442 | 以下方法不是stats集合API的一部分,而是在实现自定义stats收集器时使用的: 443 | 444 | ```py 445 | open_spider(spider) 446 | ``` 447 | 448 | 打开给定的 Spider 以收集统计信息。 449 | 450 | ```py 451 | close_spider(spider) 452 | ``` 453 | 454 | 关闭给定的 Spider 。调用之后,就不能访问或收集更多的特定统计信息。 -------------------------------------------------------------------------------- /docs/45.md: -------------------------------------------------------------------------------- 1 | # 信号 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | Scrapy广泛使用信号来通知某些事件何时发生。你可以在你的垃圾项目中捕捉到这些信号(使用 [extension](extensions.html#topics-extensions) 例如)执行其他任务或扩展scrapy以添加框外未提供的功能。 6 | 7 | 即使信号提供了几个参数,捕获它们的处理程序也不需要接受所有参数——信号调度机制只传递处理程序接收的参数。 8 | 9 | 您可以通过 [信号API](api.html#topics-api-signals) . 10 | 11 | 下面是一个简单的示例,演示如何捕获信号并执行某些操作::: 12 | 13 | ```py 14 | from scrapy import signals 15 | from scrapy import Spider 16 | 17 | class DmozSpider(Spider): 18 | name = "dmoz" 19 | allowed_domains = ["dmoz.org"] 20 | start_urls = [ 21 | "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", 22 | "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/", 23 | ] 24 | 25 | @classmethod 26 | def from_crawler(cls, crawler, *args, **kwargs): 27 | spider = super(DmozSpider, cls).from_crawler(crawler, *args, **kwargs) 28 | crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed) 29 | return spider 30 | 31 | def spider_closed(self, spider): 32 | spider.logger.info('Spider closed: %s', spider.name) 33 | 34 | def parse(self, response): 35 | pass 36 | 37 | ``` 38 | 39 | ## 延迟信号处理程序 40 | 41 | 一些信号支持返回 [Twisted deferreds](https://twistedmatrix.com/documents/current/core/howto/defer.html) from their handlers, see the [内置信号参考](#topics-signals-ref) 下面是要知道哪些。 42 | 43 | ## 内置信号参考 44 | 45 | 这是一个零碎的内置信号列表及其含义。 46 | 47 | ### engine_started 48 | 49 | ```py 50 | scrapy.signals.engine_started() 51 | ``` 52 | 53 | 当废引擎开始爬行时发送。 54 | 55 | 此信号支持从其处理程序返回延迟。 56 | 57 | 注解 58 | 59 | 此信号可能被触发 _after_ 这个 [`spider_opened`](#std:signal-spider_opened) 信号,取决于 Spider 是如何启动的。所以 **don't** 依靠这个信号 [`spider_opened`](#std:signal-spider_opened) . 60 | 61 | ### engine_stopped 62 | 63 | ```py 64 | scrapy.signals.engine_stopped() 65 | ``` 66 | 67 | 在 Scrapy 引擎停止时发送(例如,当爬行过程完成时)。 68 | 69 | 此信号支持从其处理程序返回延迟。 70 | 71 | ### item_scraped 72 | 73 | ```py 74 | scrapy.signals.item_scraped(item, response, spider) 75 | ``` 76 | 77 | 当一个项目被刮掉时发送,当它通过所有 [项目管道](item-pipeline.html#topics-item-pipeline) 阶段(不下降)。 78 | 79 | 此信号支持从其处理程序返回延迟。 80 | 81 | | 参数: | 82 | 83 | * **item** (dict or [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") object) -- 物品被刮掉了 84 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 刮掉物品的 Spider 85 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 从项目被刮掉的地方得到的响应 86 | 87 | | 88 | | --- | --- | 89 | 90 | ### item_dropped 91 | 92 | ```py 93 | scrapy.signals.item_dropped(item, response, exception, spider) 94 | ``` 95 | 96 | 从中删除项目后发送 [项目管道](item-pipeline.html#topics-item-pipeline) 当某个阶段 [`DropItem`](exceptions.html#scrapy.exceptions.DropItem "scrapy.exceptions.DropItem") 例外。 97 | 98 | 此信号支持从其处理程序返回延迟。 99 | 100 | | 参数: | 101 | 102 | * **item** (dict or [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") object) -- 从中删除的项 [项目管道](item-pipeline.html#topics-item-pipeline) 103 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 刮掉物品的 Spider 104 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 从中删除项的响应 105 | * **exception** ([`DropItem`](exceptions.html#scrapy.exceptions.DropItem "scrapy.exceptions.DropItem") exception) -- 例外情况(必须是 [`DropItem`](exceptions.html#scrapy.exceptions.DropItem "scrapy.exceptions.DropItem") 子类)导致该项被删除 106 | 107 | | 108 | | --- | --- | 109 | 110 | ### item_error 111 | 112 | ```py 113 | scrapy.signals.item_error(item, response, spider, failure) 114 | ``` 115 | 116 | 发送时 [项目管道](item-pipeline.html#topics-item-pipeline) 生成错误(即引发异常),除非 [`DropItem`](exceptions.html#scrapy.exceptions.DropItem "scrapy.exceptions.DropItem") 例外。 117 | 118 | 此信号支持从其处理程序返回延迟。 119 | 120 | | 参数: | 121 | 122 | * **item** (dict or [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") object) -- 从中删除的项 [项目管道](item-pipeline.html#topics-item-pipeline) 123 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 引发异常时正在处理的响应 124 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 引发异常的 Spider 125 | * **failure** ([Failure](https://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html) object) -- 以扭曲方式引发的异常 [Failure](https://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html) 对象 126 | 127 | | 128 | | --- | --- | 129 | 130 | ### spider_closed 131 | 132 | ```py 133 | scrapy.signals.spider_closed(spider, reason) 134 | ``` 135 | 136 | 在 Spider 关闭后发送。这可用于释放在上保留的每个 Spider 资源 [`spider_opened`](#std:signal-spider_opened) . 137 | 138 | 此信号支持从其处理程序返回延迟。 139 | 140 | | 参数: | 141 | 142 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 已关闭的 Spider 143 | * **reason** (_str_) -- 描述 Spider 关闭原因的字符串。如果它是因为 Spider 完成了抓取而关闭的,原因是 `'finished'` . 否则,如果通过调用 `close_spider` 引擎方法,则原因是 `reason` 该方法的参数(默认为 `'cancelled'` )如果发动机停机(例如,按ctrl-c停止发动机),原因将是 `'shutdown'` . 144 | 145 | | 146 | | --- | --- | 147 | 148 | ### spider_opened 149 | 150 | ```py 151 | scrapy.signals.spider_opened(spider) 152 | ``` 153 | 154 | 在 Spider 被打开爬行后发送。这通常用于为每个 Spider 保留资源,但可用于打开 Spider 时需要执行的任何任务。 155 | 156 | 此信号支持从其处理程序返回延迟。 157 | 158 | | 参数: | **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 已经打开的 Spider | 159 | | --- | --- | 160 | 161 | ### spider_idle 162 | 163 | ```py 164 | scrapy.signals.spider_idle(spider) 165 | ``` 166 | 167 | 当 Spider 空闲时发送,这意味着 Spider 没有更多: 168 | 169 | > * 等待下载的请求 170 | > * 计划的请求 171 | > * 正在项管道中处理的项 172 | 173 | 如果此信号的所有处理程序完成后空闲状态仍然存在,则引擎将开始关闭 Spider 。 Spider 完成闭合后, [`spider_closed`](#std:signal-spider_closed) 发送信号。 174 | 175 | 你可以举起 [`DontCloseSpider`](exceptions.html#scrapy.exceptions.DontCloseSpider "scrapy.exceptions.DontCloseSpider") 防止 Spider 关闭的异常。 176 | 177 | 此信号不支持从其处理程序返回延迟。 178 | 179 | | 参数: | **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 空转的 Spider | 180 | | --- | --- | 181 | 182 | 注解 183 | 184 | 在您的 [`spider_idle`](#std:signal-spider_idle) 处理程序 **not** 确保它可以防止 Spider 被关闭,尽管有时可以。这是因为如果计划程序拒绝了所有计划的请求(例如,由于重复而被筛选),那么spider可能仍然处于空闲状态。 185 | 186 | ### spider_error 187 | 188 | ```py 189 | scrapy.signals.spider_error(failure, response, spider) 190 | ``` 191 | 192 | 在spider回调生成错误(即引发异常)时发送。 193 | 194 | 此信号不支持从其处理程序返回延迟。 195 | 196 | | 参数: | 197 | 198 | * **failure** ([Failure](https://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html) object) -- 以扭曲方式引发的异常 [Failure](https://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html) 对象 199 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 引发异常时正在处理的响应 200 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 引发异常的 Spider 201 | 202 | | 203 | | --- | --- | 204 | 205 | ### request_scheduled 206 | 207 | ```py 208 | scrapy.signals.request_scheduled(request, spider) 209 | ``` 210 | 211 | 在发动机排程A时发送 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") ,稍后下载。 212 | 213 | 该信号不支持从其处理程序返回延迟。 214 | 215 | | 参数: | 216 | 217 | * **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") object) -- 到达调度程序的请求 218 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 发出请求的 Spider 219 | 220 | | 221 | | --- | --- | 222 | 223 | ### request_dropped 224 | 225 | ```py 226 | scrapy.signals.request_dropped(request, spider) 227 | ``` 228 | 229 | 发送时 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 由引擎计划稍后下载的,被调度程序拒绝。 230 | 231 | 该信号不支持从其处理程序返回延迟。 232 | 233 | | 参数: | 234 | 235 | * **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") object) -- 到达调度程序的请求 236 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 发出请求的 Spider 237 | 238 | | 239 | | --- | --- | 240 | 241 | ### request_reached_downloader 242 | 243 | ```py 244 | scrapy.signals.request_reached_downloader(request, spider) 245 | ``` 246 | 247 | 发送时 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 已到达下载程序。 248 | 249 | 该信号不支持从其处理程序返回延迟。 250 | 251 | | 参数: | 252 | 253 | * **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") object) -- 到达下载程序的请求 254 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 发出请求的 Spider 255 | 256 | | 257 | | --- | --- | 258 | 259 | ### response_received 260 | 261 | ```py 262 | scrapy.signals.response_received(response, request, spider) 263 | ``` 264 | 265 | 当发动机接收到新的 [`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") 从下载程序。 266 | 267 | 此信号不支持从其处理程序返回延迟。 268 | 269 | | 参数: | 270 | 271 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 收到的响应 272 | * **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") object) -- 生成响应的请求 273 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 响应所针对的 Spider 274 | 275 | | 276 | | --- | --- | 277 | 278 | ### response_downloaded 279 | 280 | ```py 281 | scrapy.signals.response_downloaded(response, request, spider) 282 | ``` 283 | 284 | 由下载者在 `HTTPResponse` 是下载的。 285 | 286 | 此信号不支持从其处理程序返回延迟。 287 | 288 | | 参数: | 289 | 290 | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 已下载响应 291 | * **request** ([`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") object) -- 生成响应的请求 292 | * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 响应所针对的 Spider 293 | 294 | | 295 | | --- | --- | -------------------------------------------------------------------------------- /docs/46.md: -------------------------------------------------------------------------------- 1 | # 条目导出器 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 一旦抓取了项目,您通常希望保留或导出这些项目,以便在其他应用程序中使用数据。这毕竟是抓取过程的全部目的。 6 | 7 | 为此,Scrapy为不同的输出格式(如XML、CSV或JSON)提供了一组项目导出器。 8 | 9 | ## 使用项目导出器 10 | 11 | 如果您很着急,只想使用项目导出器输出抓取的数据,请参见 [Feed 导出](feed-exports.html#topics-feed-exports) . 否则,如果您想知道项目导出器是如何工作的,或者需要更多的自定义功能(不包括在默认导出中),请继续阅读下面的内容。 12 | 13 | 为了使用项导出器,必须用它所需的参数实例化它。每个项目导出器需要不同的参数,因此请检查每个导出器文档以确保 [内置项导出器引用](#topics-exporters-reference) . 在实例化导出器之后,必须: 14 | 15 | 1。调用方法 [`start_exporting()`](#scrapy.exporters.BaseItemExporter.start_exporting "scrapy.exporters.BaseItemExporter.start_exporting") 以便发出出口过程开始的信号 16 | 17 | 2。调用给 [`export_item()`](#scrapy.exporters.BaseItemExporter.export_item "scrapy.exporters.BaseItemExporter.export_item") 要导出的每个项的方法 18 | 19 | 三。最后调用给 [`finish_exporting()`](#scrapy.exporters.BaseItemExporter.finish_exporting "scrapy.exporters.BaseItemExporter.finish_exporting") 发出输出过程结束的信号 20 | 21 | 在这里你可以看到 [Item Pipeline](item-pipeline.html) 它使用多个项目导出器,根据其中一个字段的值将抓取的项目分组到不同的文件中: 22 | 23 | ```py 24 | from scrapy.exporters import XmlItemExporter 25 | 26 | class PerYearXmlExportPipeline(object): 27 | """Distribute items across multiple XML files according to their 'year' field""" 28 | 29 | def open_spider(self, spider): 30 | self.year_to_exporter = {} 31 | 32 | def close_spider(self, spider): 33 | for exporter in self.year_to_exporter.values(): 34 | exporter.finish_exporting() 35 | exporter.file.close() 36 | 37 | def _exporter_for_item(self, item): 38 | year = item['year'] 39 | if year not in self.year_to_exporter: 40 | f = open('{}.xml'.format(year), 'wb') 41 | exporter = XmlItemExporter(f) 42 | exporter.start_exporting() 43 | self.year_to_exporter[year] = exporter 44 | return self.year_to_exporter[year] 45 | 46 | def process_item(self, item, spider): 47 | exporter = self._exporter_for_item(item) 48 | exporter.export_item(item) 49 | return item 50 | 51 | ``` 52 | 53 | ## 项字段的序列化 54 | 55 | 默认情况下,字段值是未修改地传递给基础序列化库的,如何序列化字段值的决定被委托给每个特定的序列化库。 56 | 57 | 但是,您可以自定义每个字段值的序列化方式。 在传递到序列化库之前. 58 | 59 | 有两种方法可以自定义字段序列化的方式,下面将介绍这两种方法。 60 | 61 | ### 1。在字段中声明序列化程序 62 | 63 | 如果你使用 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") 可以在中声明序列化程序 [field metadata](items.html#topics-items-fields) . 序列化程序必须是可调用的,它接收值并返回其序列化形式。 64 | 65 | 例子:: 66 | 67 | ```py 68 | import scrapy 69 | 70 | def serialize_price(value): 71 | return '$ %s' % str(value) 72 | 73 | class Product(scrapy.Item): 74 | name = scrapy.Field() 75 | price = scrapy.Field(serializer=serialize_price) 76 | 77 | ``` 78 | 79 | ### 2。重写serialize_field()方法 80 | 81 | 您还可以覆盖 [`serialize_field()`](#scrapy.exporters.BaseItemExporter.serialize_field "scrapy.exporters.BaseItemExporter.serialize_field") 方法自定义字段值的导出方式。 82 | 83 | 确保调用基类 [`serialize_field()`](#scrapy.exporters.BaseItemExporter.serialize_field "scrapy.exporters.BaseItemExporter.serialize_field") 方法。 84 | 85 | 例子:: 86 | 87 | ```py 88 | from scrapy.exporter import XmlItemExporter 89 | 90 | class ProductXmlExporter(XmlItemExporter): 91 | 92 | def serialize_field(self, field, name, value): 93 | if field == 'price': 94 | return '$ %s' % str(value) 95 | return super(Product, self).serialize_field(field, name, value) 96 | 97 | ``` 98 | 99 | ## 内置项导出器引用 100 | 101 | 这是与废料捆绑在一起的物品出口商名单。其中一些包含输出示例,假设您正在导出这两个项: 102 | 103 | ```py 104 | Item(name='Color TV', price='1200') 105 | Item(name='DVD player', price='200') 106 | 107 | ``` 108 | 109 | ### BaseItemExporter 110 | 111 | ```py 112 | class scrapy.exporters.BaseItemExporter(fields_to_export=None, export_empty_fields=False, encoding='utf-8', indent=0) 113 | ``` 114 | 115 | 这是所有项目导出器的(抽象)基类。它支持所有(具体)项目导出器使用的公共特性,例如定义要导出的字段、是否导出空字段或要使用的编码。 116 | 117 | 这些特性可以通过填充其各自实例属性的构造函数参数进行配置: [`fields_to_export`](#scrapy.exporters.BaseItemExporter.fields_to_export "scrapy.exporters.BaseItemExporter.fields_to_export") , [`export_empty_fields`](#scrapy.exporters.BaseItemExporter.export_empty_fields "scrapy.exporters.BaseItemExporter.export_empty_fields") , [`encoding`](#scrapy.exporters.BaseItemExporter.encoding "scrapy.exporters.BaseItemExporter.encoding") , [`indent`](#scrapy.exporters.BaseItemExporter.indent "scrapy.exporters.BaseItemExporter.indent") . 118 | 119 | ```py 120 | export_item(item) 121 | ``` 122 | 123 | 导出给定项。此方法必须在子类中实现。 124 | 125 | ```py 126 | serialize_field(field, name, value) 127 | ``` 128 | 129 | 返回给定字段的序列化值。如果要控制特定字段或值的序列化/导出方式,可以重写此方法(在自定义项导出器中)。 130 | 131 | 默认情况下,此方法查找序列化程序 [declared in the item field](#topics-exporters-serializers) 并返回将该序列化程序应用于该值的结果。如果找不到序列化程序,它将返回除 `unicode` 编码到的值 `str` 使用中声明的编码 [`encoding`](#scrapy.exporters.BaseItemExporter.encoding "scrapy.exporters.BaseItemExporter.encoding") 属性。 132 | 133 | | 参数: | 134 | 135 | * **field** ([`Field`](items.html#scrapy.item.Field "scrapy.item.Field") object or an empty dict) -- 正在序列化的字段。如果正在导出原始dict(不是 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") ) _field_ 值是空的dict。 136 | * **name** (_str_) -- 正在序列化的字段的名称 137 | * **value** -- 正在序列化的值 138 | 139 | | 140 | | --- | --- | 141 | 142 | ```py 143 | start_exporting() 144 | ``` 145 | 146 | 指示导出过程的开始。某些导出器可能会使用此命令生成某些必需的头(例如, [`XmlItemExporter`](#scrapy.exporters.XmlItemExporter "scrapy.exporters.XmlItemExporter") )在导出任何项之前必须调用此方法。 147 | 148 | ```py 149 | finish_exporting() 150 | ``` 151 | 152 | 发出输出过程结束的信号。一些导出器可能会使用此命令生成一些必需的页脚(例如, [`XmlItemExporter`](#scrapy.exporters.XmlItemExporter "scrapy.exporters.XmlItemExporter") )在没有其他要导出的项之后,必须始终调用此方法。 153 | 154 | ```py 155 | fields_to_export 156 | ``` 157 | 158 | 具有要导出的字段名称的列表,如果要导出所有字段,则为“无”。默认为无。 159 | 160 | 一些出口商(如 [`CsvItemExporter`](#scrapy.exporters.CsvItemExporter "scrapy.exporters.CsvItemExporter") )遵守此属性中定义的字段的顺序。 161 | 162 | 有些导出者可能需要字段“到”导出列表,以便在spider返回dict时正确导出数据(而不是 `Item` 实例)。 163 | 164 | ```py 165 | export_empty_fields 166 | ``` 167 | 168 | 是否在导出的数据中包含空/未填充的项字段。默认为 `False` . 一些出口商(如 [`CsvItemExporter`](#scrapy.exporters.CsvItemExporter "scrapy.exporters.CsvItemExporter") )忽略此属性并始终导出所有空字段。 169 | 170 | 对dict项忽略此选项。 171 | 172 | ```py 173 | encoding 174 | ``` 175 | 176 | 将用于编码Unicode值的编码。这只影响unicode值(这些值总是使用此编码序列化到str)。其他值类型不变地传递给特定的序列化库。 177 | 178 | ```py 179 | indent 180 | ``` 181 | 182 | 用于在每个级别上缩进输出的空间量。默认为 `0` . 183 | 184 | * `indent=None` 选择最紧凑的表示形式,同一行中的所有项都没有缩进 185 | * `indent<=0` 每个项目都在自己的行上,没有缩进 186 | * `indent>0` 每一项都在自己的行上,用提供的数值缩进 187 | 188 | ### XmlItemExporter 189 | 190 | ```py 191 | class scrapy.exporters.XmlItemExporter(file, item_element='item', root_element='items', **kwargs) 192 | ``` 193 | 194 | 将XML格式的项导出到指定的文件对象。 195 | 196 | | 参数: | 197 | 198 | * **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) 199 | * **root_element** (_str_) -- 导出的XML中根元素的名称。 200 | * **item_element** (_str_) -- 导出的XML中每个item元素的名称。 201 | 202 | | 203 | | --- | --- | 204 | 205 | 此构造函数的其他关键字参数将传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 建造师。 206 | 207 | 该出口商的典型产出为: 208 | 209 | ```py 210 | 211 | 212 | 213 | Color TV 214 | 1200 215 | 216 | 217 | DVD player 218 | 200 219 | 220 | 221 | 222 | ``` 223 | 224 | 除非在 `serialize_field()` 方法,多值字段通过序列化 `<value>` 元素。这是为了方便起见,因为多值字段非常常见。 225 | 226 | 例如,项目: 227 | 228 | ```py 229 | Item(name=['John', 'Doe'], age='23') 230 | 231 | ``` 232 | 233 | 将序列化为: 234 | 235 | ```py 236 | 237 | 238 | 239 | 240 | John 241 | Doe 242 | 243 | 23 244 | 245 | 246 | 247 | ``` 248 | 249 | ### CsvItemExporter 250 | 251 | ```py 252 | class scrapy.exporters.CsvItemExporter(file, include_headers_line=True, join_multivalued=', ', **kwargs) 253 | ``` 254 | 255 | 将csv格式的项目导出到给定的文件(如对象)。如果 `fields_to_export` 属性已设置,将用于定义csv列及其顺序。这个 `export_empty_fields` 属性对此导出程序没有影响。 256 | 257 | | 参数: | 258 | 259 | * **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) 260 | * **include_headers_line** (_str_) -- 如果启用,则使导出器输出一个标题行,其中字段名取自 [`BaseItemExporter.fields_to_export`](#scrapy.exporters.BaseItemExporter.fields_to_export "scrapy.exporters.BaseItemExporter.fields_to_export") 或第一个导出项字段。 261 | * **join_multivalued** -- 如果找到,将用于联接多值字段的字符。 262 | 263 | | 264 | | --- | --- | 265 | 266 | 此构造函数的其他关键字参数将传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 构造函数,以及 [csv.writer](https://docs.python.org/2/library/csv.html#csv.writer) 构造函数,因此可以使用 `csv.writer` 自定义此导出程序的构造函数参数。 267 | 268 | 该出口商的典型产出为: 269 | 270 | ```py 271 | product,price 272 | Color TV,1200 273 | DVD player,200 274 | 275 | ``` 276 | 277 | ### PickleItemExporter 278 | 279 | ```py 280 | class scrapy.exporters.PickleItemExporter(file, protocol=0, **kwargs) 281 | ``` 282 | 283 | 将pickle格式的项导出到给定的文件(如对象)。 284 | 285 | | 参数: | 286 | 287 | * **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) 288 | * **protocol** (_int_) -- 要使用的pickle协议。 289 | 290 | | 291 | | --- | --- | 292 | 293 | 有关详细信息,请参阅 [pickle module documentation](https://docs.python.org/2/library/pickle.html) . 294 | 295 | 此构造函数的其他关键字参数将传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 建造师。 296 | 297 | pickle不是人类可读的格式,因此没有提供输出示例。 298 | 299 | ### PprintItemExporter 300 | 301 | ```py 302 | class scrapy.exporters.PprintItemExporter(file, **kwargs) 303 | ``` 304 | 305 | 以漂亮的打印格式将项目导出到指定的文件对象。 306 | 307 | | 参数: | **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) | 308 | | --- | --- | 309 | 310 | 此构造函数的其他关键字参数将传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 建造师。 311 | 312 | 该出口商的典型产出为: 313 | 314 | ```py 315 | {'name': 'Color TV', 'price': '1200'} 316 | {'name': 'DVD player', 'price': '200'} 317 | 318 | ``` 319 | 320 | 较长的行(如果存在)的格式很好。 321 | 322 | ### JsonItemExporter 323 | 324 | ```py 325 | class scrapy.exporters.JsonItemExporter(file, **kwargs) 326 | ``` 327 | 328 | 以JSON格式将项目导出到指定的文件(如对象),将所有对象作为对象列表写入。附加的构造函数参数传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 构造函数,以及 [JSONEncoder](https://docs.python.org/2/library/json.html#json.JSONEncoder) 构造函数,因此可以使用 [JSONEncoder](https://docs.python.org/2/library/json.html#json.JSONEncoder) 自定义此导出程序的构造函数参数。 329 | 330 | | 参数: | **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) | 331 | | --- | --- | 332 | 333 | 该出口商的典型产出为: 334 | 335 | ```py 336 | [{"name": "Color TV", "price": "1200"}, 337 | {"name": "DVD player", "price": "200"}] 338 | 339 | ``` 340 | 341 | 警告 342 | 343 | JSON是一种非常简单和灵活的序列化格式,但是由于是增量的(aka),它不能很好地扩展到大量的数据中。流模式)解析在JSON解析器(在任何语言上)中都不受很好的支持(如果有),而且大多数解析器只是解析内存中的整个对象。如果您希望JSON的强大性和简单性具有更流友好的格式,请考虑使用 [`JsonLinesItemExporter`](#scrapy.exporters.JsonLinesItemExporter "scrapy.exporters.JsonLinesItemExporter") 或者将输出分成多个块。 344 | 345 | ### JsonLinesItemExporter 346 | 347 | ```py 348 | class scrapy.exporters.JsonLinesItemExporter(file, **kwargs) 349 | ``` 350 | 351 | 以JSON格式将项目导出到指定的文件(如对象),每行写入一个JSON编码的项目。附加的构造函数参数传递给 [`BaseItemExporter`](#scrapy.exporters.BaseItemExporter "scrapy.exporters.BaseItemExporter") 构造函数,以及 [JSONEncoder](https://docs.python.org/2/library/json.html#json.JSONEncoder) 构造函数,因此可以使用 [JSONEncoder](https://docs.python.org/2/library/json.html#json.JSONEncoder) 自定义此导出程序的构造函数参数。 352 | 353 | | 参数: | **file** -- 用于导出数据的类似文件的对象。它的 `write` 方法应接受 `bytes` (以二进制模式打开的磁盘文件, `io.BytesIO` 物体等) | 354 | | --- | --- | 355 | 356 | 该出口商的典型产出为: 357 | 358 | ```py 359 | {"name": "Color TV", "price": "1200"} 360 | {"name": "DVD player", "price": "200"} 361 | 362 | ``` 363 | 364 | 不同于 [`JsonItemExporter`](#scrapy.exporters.JsonItemExporter "scrapy.exporters.JsonItemExporter") ,此导出程序生成的格式非常适合序列化大量数据。 -------------------------------------------------------------------------------- /docs/47.md: -------------------------------------------------------------------------------- 1 | # 其余所有 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/49.md: -------------------------------------------------------------------------------- 1 | # 为 Scrapy 贡献 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 重要 6 | 7 | 在https://docs.scrapy.org/en/master/contributing.html上仔细检查您是否正在阅读此文档的最新版本。 8 | 9 | 有很多方法可以让你的生活一团糟。以下是其中一些: 10 | 11 | * 关于Scrapy的博客。告诉全世界你是如何使用Scrapy的。这将有助于新来者提供更多的示例,并有助于 Scrapy 的项目增加其可见性。 12 | * 报告Bug并请求 [issue tracker](https://github.com/scrapy/scrapy/issues) ,尝试遵循 [Reporting bugs](#reporting-bugs) 下面。 13 | * 提交新功能和/或错误修复的补丁。请阅读 [编码补丁](#writing-patches) 和 [Submitting patches](#id2) 下面是关于如何编写和提交补丁的详细信息。 14 | * 加入 [Scrapy subreddit](https://reddit.com/r/scrapy) 分享你对如何改善垃圾的想法。我们总是乐于接受建议。 15 | * 回答一些琐碎的问题 [Stack Overflow](https://stackoverflow.com/questions/tagged/scrapy) . 16 | 17 | ## 报告错误 18 | 19 | 注解 20 | 21 | 请报告安全问题 **only** 发送至scrapy-[security@googlegroups.com](mailto:security%40googlegroups.com)。这是一个私人列表,只对受信任的垃圾开发者开放,其档案不公开。 22 | 23 | 写得好的bug报告非常有用,因此在报告新bug时,请记住以下指导原则。 24 | 25 | * 检查 [FAQ](faq.html#faq) 首先看看你的问题是否在一个众所周知的问题中得到解决。 26 | * 如果您对 Scrapy 的使用有一般性问题,请在 [Stack Overflow](https://stackoverflow.com/questions/tagged/scrapy) (使用“ Scrapy ”标签)。 27 | * 检查 [open issues](https://github.com/scrapy/scrapy/issues) 查看问题是否已报告。如果有,不要驳回报告,而是检查记录和评论。如果您有其他有用信息,请留言或考虑 [sending a pull request](#writing-patches) 修理好了。 28 | * 搜索 [scrapy-users](https://groups.google.com/forum/#!forum/scrapy-users) 列表和 [Scrapy subreddit](https://reddit.com/r/scrapy) 看看是否在那里讨论过,或者你不确定你所看到的是否是一个bug。你也可以在 `#scrapy` IRC通道。 29 | * 写 完整、可复制、特定的错误报告. 测试用例越小越好。请记住,其他开发人员不会让您的项目复制该bug,因此请包括复制该bug所需的所有相关文件。例如,请参见StackOverflow的《创建 [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) 展示问题。 30 | * 提供一个完整的可复制示例的最棒的方法是发送一个pull请求,该请求将一个失败的测试用例添加到Scrapy测试套件中(请参见 [正在提交修补程序](#submitting-patches) )即使你不打算自己解决这个问题,这也是有帮助的。 31 | * 包括的输出 `scrapy version -v` 因此,开发人员在您的bug上准确地知道它发生在哪个版本和平台上,这通常对复制它非常有帮助,或者知道它是否已经被修复了。 32 | 33 | ## 编码补丁 34 | 35 | 补丁编写得越好,它被接受的机会就越高,合并的速度就越快。 36 | 37 | 写得好的补丁应该: 38 | 39 | * 包含特定更改所需的最小代码量。小补丁更容易查看和合并。因此,如果您进行了多个更改(或错误修复),请考虑为每个更改提交一个补丁。不要将多个更改折叠为单个修补程序。对于较大的更改,请考虑使用修补程序队列。 40 | * 通过所有单元测试。见 [Running tests](#running-tests) 下面。 41 | * 包括一个(或多个)测试用例,检查修复的错误或添加的新功能。见 [Writing tests](#writing-tests) 下面。 42 | * 如果要添加或更改公共(文档化)API,请在同一补丁中包含文档更改。见 [Documentation policies](#documentation-policies) 下面。 43 | 44 | ## 正在提交修补程序 45 | 46 | 提交补丁的最佳方法是发布 [pull request](https://help.github.com/send-pull-requests/) 在Github上,可以选择先创建一个新问题。 47 | 48 | 记住解释什么是固定的或新的功能(它是什么,为什么需要它,等等)。您包含的信息越多,核心开发人员就越容易理解和接受您的补丁。 49 | 50 | 您也可以在创建补丁之前讨论新的功能(或bug修复),但是准备好一个补丁来说明您的论点并表明您已经在主题中添加了一些额外的思想总是很好的。一个好的起点是在Github上发送一个拉请求。它可以很简单地说明您的想法,并将文档/测试留到稍后,在这个想法被验证和证明是有用的之后。或者,您可以在 [Scrapy subreddit](https://reddit.com/r/scrapy) 先讨论你的想法。 51 | 52 | 有时,对于您想要解决的问题,有一个现有的请求请求,由于某种原因而停止。通常拉请求的方向是正确的,但更改是由 Scrapy 维护人员请求的,而原始拉请求作者没有时间处理它们。在这种情况下,考虑接受这个拉请求:打开一个新的拉请求,其中包含来自原始拉请求的所有提交,以及解决所提出问题的其他更改。这样做有很大的帮助;一旦原作者被承认遵守了自己的承诺,就不会被认为是不礼貌的。 53 | 54 | 您可以通过运行 `git fetch upstream pull/$PR_NUMBER/head:$BRANCH_NAME_TO_CREATE` (将“上游”替换为Scrapy存储库的远程名称, `$PR_NUMBER` 带有拉请求的ID,以及 `$BRANCH_NAME_TO_CREATE` 使用要在本地创建的分支的名称)。另请参见:[https://help.github.com/articles/checking](https://help.github.com/articles/checking) out pull requests locally/在本地修改非活动的pull请求。 55 | 56 | 在编写Github Pull请求时,请尽量保持标题简短但具有描述性。例如,对于bug 411:“如果启动请求中出现异常,则scrapy将挂起”首选“当启动请求中出现异常时修复挂起”(而不是“修复为411”)。完整的标题使浏览问题跟踪器变得容易。 57 | 58 | 最后,试着保持审美的变化( [**PEP 8**](https://www.python.org/dev/peps/pep-0008) 合规性、未使用的进口删除等)与功能更改分开提交。这将使pull请求更容易审查,更容易合并。 59 | 60 | ## 编码风格 61 | 62 | 编写要包含在Scrapy中的代码时,请遵循以下编码约定: 63 | 64 | * 除非另有规定,遵循 [**PEP 8**](https://www.python.org/dev/peps/pep-0008) . 65 | * 如果可以提高代码的可读性,可以使用长度超过80个字符的行。 66 | * 不要在您贡献的代码中输入您的名字;Git提供了足够的元数据来标识代码的作者。有关安装说明,请参阅https://help.github.com/articles/setting-your-username-in-git/。 67 | 68 | ## 文档策略 69 | 70 | 对于API成员(类、方法等)的参考文档,请使用docstring并确保sphinx文档使用 [autodoc](http://www.sphinx-doc.org/en/stable/ext/autodoc.html) 用于拉取docstrings的扩展。API参考文档应该是面向IDE的:简短,切中要害,它可能提供简短的示例。 71 | 72 | 其他类型的文档(如教程或主题)应包含在 `docs/` 目录。这包括特定于API成员的文档,但超出了API参考文档。 73 | 74 | 在任何情况下,如果文档字符串中包含某些内容,请使用 [autodoc](http://www.sphinx-doc.org/en/stable/ext/autodoc.html) 扩展名,用于将docstring拉入文档,而不是在 `docs/` 目录。 75 | 76 | ## 测验 77 | 78 | 测试是使用 [Twisted unit-testing framework](https://twistedmatrix.com/documents/current/core/development/policy/test-standard.html) ,运行测试需要 [tox](https://pypi.python.org/pypi/tox) . 79 | 80 | ### 运行试验 81 | 82 | 确保你最近有足够的 [tox](https://pypi.python.org/pypi/tox) 安装: 83 | 84 | > `tox --version` 85 | 86 | 如果您的版本早于1.7.0,请先更新: 87 | 88 | > `pip install -U tox` 89 | 90 | 要运行所有测试,请转到Scrapy源代码的根目录并运行: 91 | 92 | > `tox` 93 | 94 | 运行特定的测试(比如 `tests/test_loader.py` 用途: 95 | 96 | > `tox -- tests/test_loader.py` 97 | 98 | 查看覆盖率报告安装 [coverage](https://pypi.python.org/pypi/coverage) ( `pip install coverage` 然后运行: 99 | 100 | > `coverage report` 101 | 102 | 见输出 `coverage --help` 获取更多选项,如HTML或XML报告。 103 | 104 | ### 写作测试 105 | 106 | 所有功能(包括新功能和错误修复)都必须包含一个测试用例,以检查它是否按预期工作,因此如果您希望补丁能够更快地被接受,请包含对它们的测试。 107 | 108 | Scrapy使用单元测试,位于 [tests/](https://github.com/scrapy/scrapy/tree/master/tests) 目录。它们的模块名通常类似于所测试模块的完整路径。例如,项目加载器代码位于:: 109 | 110 | ```py 111 | scrapy.loader 112 | 113 | ``` 114 | 115 | 他们的单元测试在: 116 | 117 | ```py 118 | tests/test_loader.py 119 | 120 | ``` -------------------------------------------------------------------------------- /docs/50.md: -------------------------------------------------------------------------------- 1 | # 版本控制和API稳定性 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | ## 版本 6 | 7 | Scrapy 版本号有3个数字:_A.B.C_ 8 | 9 | * _A_ 是主要版本。这将很少改变,并将意味着非常大的变化。 10 | * _B_ 是发行号。这将包括许多变化,包括可能破坏向后兼容性的特性和东西,尽管我们努力将这些情况保持在最低限度。 11 | * _C_ 是错误修复版本号。 12 | 13 | 在 [release notes](news.html#news) ,可能需要特别注意才能升级。 14 | 15 | 开发版本不遵循3号版本,通常发布为 `dev` 后缀版本,例如 `1.3dev` . 16 | 17 | 注解 18 | 19 | 带Scrapy 0.*系列,使用Scrapy [odd-numbered versions for development releases](https://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases) . 从Scrapy1.0开始就不再是这样了。 20 | 21 | 从Scrapy1.0开始,所有版本都应视为生产就绪。 22 | 23 | 例如: 24 | 25 | * _1.1.1_ 是的第一个错误修复版本 _1.1_ 系列(生产中使用安全) 26 | 27 | ## API稳定性 28 | 29 | API的稳定性是 _1.0_ 释放。 30 | 31 | 以单个破折号开头的方法或函数( `_` )是私人的,不应该被当作稳定的。 32 | 33 | 另外,请记住,稳定并不意味着完整:稳定的API可以增加新的方法或功能,但是现有的方法应该保持相同的工作方式。 -------------------------------------------------------------------------------- /docs/6.md: -------------------------------------------------------------------------------- 1 | # 实例 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 最好的学习方法是举例,而Scrapy也不例外。因此,有一个名为Quotesbot_uu的Scrapy项目示例,您可以使用它来玩并了解更多关于Scrapy的信息。它包含两个用于http://quotes.toscrape.com的spider,一个使用css选择器,另一个使用xpath表达式。 6 | 7 | QuotesBot_u项目可从以下网址获得:[https://github.com/scrappy/QuotesBot](https://github.com/scrappy/QuotesBot)。您可以在项目的自述文件中找到关于它的更多信息。 8 | 9 | 如果您熟悉Git,可以签出代码。否则,您可以通过单击以zip文件的形式下载项目。 [here](https://github.com/scrapy/quotesbot/archive/master.zip) . -------------------------------------------------------------------------------- /docs/7.md: -------------------------------------------------------------------------------- 1 | # 基本概念 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) -------------------------------------------------------------------------------- /docs/8.md: -------------------------------------------------------------------------------- 1 | # 命令行工具 2 | 3 | > 译者:[OSGeo 中国](https://www.osgeo.cn/) 4 | 5 | 0.10 新版功能. 6 | 7 | Scrapy 通过控制 `scrapy` 命令行工具,这里称为“scrapy工具”,用于区分子命令,我们称之为“命令”或“scrapy命令”。 8 | 9 | Scrapy工具提供了多个命令,用于多种目的,每个命令接受一组不同的参数和选项。 10 | 11 | (The `scrapy deploy` 命令已在1.0中删除,以支持独立的 `scrapyd-deploy` . 见 [Deploying your project](https://scrapyd.readthedocs.io/en/latest/deploy.html) ) 12 | 13 | ## 配置设置 14 | 15 | Scrapy将查找ini样式的配置参数 `scrapy.cfg` 标准位置的文件: 16 | 17 | 1. `/etc/scrapy.cfg` 或 `c:\scrapy\scrapy.cfg` (全系统) 18 | 2. `~/.config/scrapy.cfg` ( `$XDG_CONFIG_HOME` ) `~/.scrapy.cfg` ( `$HOME` )用于全局(用户范围)设置,以及 19 | 3. `scrapy.cfg` 在Scrapy项目的根目录中(参见下一节)。 20 | 21 | 这些文件中的设置按列出的首选顺序合并:用户定义的值比系统范围的默认值具有更高的优先级,并且在定义时,项目范围的设置将覆盖所有其他设置。 22 | 23 | Scrapy还可以理解并通过许多环境变量进行配置。目前有: 24 | 25 | * `SCRAPY_SETTINGS_MODULE` (见 [指定设置](settings.html#topics-settings-module-envvar) ) 26 | * `SCRAPY_PROJECT` (见 [在项目之间共享根目录](#topics-project-envvar) ) 27 | * `SCRAPY_PYTHON_SHELL` (见 [Scrapy shell](shell.html#topics-shell) ) 28 | 29 | ## Scrapy 项目的默认结构 30 | 31 | 在深入研究命令行工具及其子命令之前,让我们先了解一个零碎项目的目录结构。 32 | 33 | 尽管可以修改,但默认情况下,所有零碎项目都具有相同的文件结构,类似于: 34 | 35 | ```py 36 | scrapy.cfg 37 | myproject/ 38 | __init__.py 39 | items.py 40 | middlewares.py 41 | pipelines.py 42 | settings.py 43 | spiders/ 44 | __init__.py 45 | spider1.py 46 | spider2.py 47 | ... 48 | 49 | ``` 50 | 51 | 目录 `scrapy.cfg` 文件驻留称为 项目根目录. 该文件包含定义项目设置的python模块的名称。下面是一个例子: 52 | 53 | ```py 54 | [settings] 55 | default = myproject.settings 56 | 57 | ``` 58 | 59 | ## 在项目之间共享根目录 60 | 61 | 一个项目根目录,其中包含 `scrapy.cfg` ,可以由多个零碎项目共享,每个项目都有自己的设置模块。 62 | 63 | 在这种情况下,必须为下面的设置模块定义一个或多个别名 `[settings]` 在你 `scrapy.cfg` 文件:: 64 | 65 | ```py 66 | [settings] 67 | default = myproject1.settings 68 | project1 = myproject1.settings 69 | project2 = myproject2.settings 70 | 71 | ``` 72 | 73 | 默认情况下, `scrapy` 命令行工具将使用 `default` 设置。使用 `SCRAPY_PROJECT` 用于指定其他项目的环境变量 `scrapy` 使用: 74 | 75 | ```py 76 | $ scrapy settings --get BOT_NAME 77 | Project 1 Bot 78 | $ export SCRAPY_PROJECT=project2 79 | $ scrapy settings --get BOT_NAME 80 | Project 2 Bot 81 | 82 | ``` 83 | 84 | ## 使用 `scrapy` 工具 85 | 86 | 您可以通过运行无参数的scrapy工具开始,它将打印一些用法帮助和可用的命令: 87 | 88 | ```py 89 | Scrapy X.Y - no active project 90 | 91 | Usage: 92 | scrapy [options] [args] 93 | 94 | Available commands: 95 | crawl Run a spider 96 | fetch Fetch a URL using the Scrapy downloader 97 | [...] 98 | 99 | ``` 100 | 101 | 如果您在一个零碎的项目中,第一行将打印当前活动的项目。在本例中,它是从项目外部运行的。如果从项目内部运行,它将打印如下内容: 102 | 103 | ```py 104 | Scrapy X.Y - project: myproject 105 | 106 | Usage: 107 | scrapy [options] [args] 108 | 109 | [...] 110 | 111 | ``` 112 | 113 | ### 创建项目 114 | 115 | 你通常会做的第一件事就是 `scrapy` 工具是创建零碎项目: 116 | 117 | ```py 118 | scrapy startproject myproject [project_dir] 119 | 120 | ``` 121 | 122 | 它将在 `project_dir` 目录。如果 `project_dir` 没有指定, `project_dir` 将与 `myproject` . 123 | 124 | 接下来,进入新的项目目录: 125 | 126 | ```py 127 | cd project_dir 128 | 129 | ``` 130 | 131 | 你已经准备好使用 `scrapy` 从那里管理和控制项目的命令。 132 | 133 | ### 控制性项目 134 | 135 | 你使用 `scrapy` 从项目内部使用工具来控制和管理它们。 136 | 137 | 例如,要创建新的 Spider : 138 | 139 | ```py 140 | scrapy genspider mydomain mydomain.com 141 | 142 | ``` 143 | 144 | 一些下流的命令(比如 [`crawl`](#std:command-crawl) )必须从零碎的项目内部运行。见 [commands reference](#topics-commands-ref) 下面是关于必须从项目内部运行哪些命令的详细信息,而不是。 145 | 146 | 还要记住,当从内部项目运行某些命令时,它们的行为可能略有不同。例如,fetch命令将使用 Spider 重写的行为(例如 `user_agent` 属性来重写用户代理)如果要获取的URL与某个特定的 Spider 相关联。这是故意的,因为 `fetch` 命令用于检查 Spider 如何下载页面。 147 | 148 | ## 可用工具命令 149 | 150 | 本节包含可用的内置命令列表,其中包含说明和一些用法示例。记住,您可以通过运行以下命令获取有关每个命令的更多信息: 151 | 152 | ```py 153 | scrapy -h 154 | 155 | ``` 156 | 157 | 您可以使用以下命令查看所有可用命令: 158 | 159 | ```py 160 | scrapy -h 161 | 162 | ``` 163 | 164 | 有两种命令,一种是只从零碎项目(特定于项目的命令)内部工作的命令,另一种是不使用活动零碎项目(全局命令)的命令,尽管从项目内部运行时它们的行为可能略有不同(因为它们将使用项目覆盖设置)。 165 | 166 | 全局命令: 167 | 168 | * [`startproject`](#std:command-startproject) 169 | * [`genspider`](#std:command-genspider) 170 | * [`settings`](#std:command-settings) 171 | * [`runspider`](#std:command-runspider) 172 | * [`shell`](#std:command-shell) 173 | * [`fetch`](#std:command-fetch) 174 | * [`view`](#std:command-view) 175 | * [`version`](#std:command-version) 176 | 177 | 仅Project命令: 178 | 179 | * [`crawl`](#std:command-crawl) 180 | * [`check`](#std:command-check) 181 | * [`list`](#std:command-list) 182 | * [`edit`](#std:command-edit) 183 | * [`parse`](#std:command-parse) 184 | * [`bench`](#std:command-bench) 185 | 186 | ### 启动项目 187 | 188 | * Syntax: `scrapy startproject <project_name> [project_dir]` 189 | * 需要项目:_否_ 190 | 191 | 创建一个名为 `project_name` 下 `project_dir` 目录。如果 `project_dir` 没有指定, `project_dir` 将与 `project_name` . 192 | 193 | 使用实例: 194 | 195 | ```py 196 | $ scrapy startproject myproject 197 | 198 | ``` 199 | 200 | ### 基因 Spider 201 | 202 | * Syntax: `scrapy genspider [-t template] <name> <domain>` 203 | * 需要项目:_否_ 204 | 205 | 在当前文件夹或当前项目的 `spiders` 文件夹(如果从项目内部调用)。这个 `<name>` 参数设置为spider的 `name` ,同时 `<domain>` 用于生成 `allowed_domains` 和 `start_urls` Spider 的属性。 206 | 207 | 使用实例: 208 | 209 | ```py 210 | $ scrapy genspider -l 211 | Available templates: 212 | basic 213 | crawl 214 | csvfeed 215 | xmlfeed 216 | 217 | $ scrapy genspider example example.com 218 | Created spider 'example' using template 'basic' 219 | 220 | $ scrapy genspider -t crawl scrapyorg scrapy.org 221 | Created spider 'scrapyorg' using template 'crawl' 222 | 223 | ``` 224 | 225 | 这只是一个基于预先定义的模板创建spider的快捷命令,但肯定不是创建spider的唯一方法。您可以自己创建 Spider 源代码文件,而不是使用这个命令。 226 | 227 | ### 爬行 228 | 229 | * Syntax: `scrapy crawl <spider>` 230 | * 需要项目:_是_ 231 | 232 | 开始用 Spider 爬行。 233 | 234 | 用法示例: 235 | 236 | ```py 237 | $ scrapy crawl myspider 238 | [ ... myspider starts crawling ... ] 239 | 240 | ``` 241 | 242 | ### 检查 243 | 244 | * Syntax: `scrapy check [-l] <spider>` 245 | * 需要项目:_是_ 246 | 247 | 运行合同检查。 248 | 249 | 用法示例: 250 | 251 | ```py 252 | $ scrapy check -l 253 | first_spider 254 | * parse 255 | * parse_item 256 | second_spider 257 | * parse 258 | * parse_item 259 | 260 | $ scrapy check 261 | [FAILED] first_spider:parse_item 262 | >>> 'RetailPricex' field is missing 263 | 264 | [FAILED] first_spider:parse 265 | >>> Returned 92 requests, expected 0..4 266 | 267 | ``` 268 | 269 | ### 列表 270 | 271 | * Syntax: `scrapy list` 272 | * 需要项目:_是_ 273 | 274 | 列出当前项目中所有可用的spider。每行输出一个 Spider 。 275 | 276 | 使用实例: 277 | 278 | ```py 279 | $ scrapy list 280 | spider1 281 | spider2 282 | 283 | ``` 284 | 285 | ### 编辑 286 | 287 | * Syntax: `scrapy edit <spider>` 288 | * 需要项目:_是_ 289 | 290 | 使用中定义的编辑器编辑给定的 Spider `EDITOR` 环境变量或(如果未设置) [`EDITOR`](settings.html#std:setting-EDITOR) 设置。 291 | 292 | 这个命令仅作为最常见情况下的快捷方式提供,开发人员当然可以自由选择任何工具或IDE来编写和调试spider。 293 | 294 | 使用实例: 295 | 296 | ```py 297 | $ scrapy edit spider1 298 | 299 | ``` 300 | 301 | ### 取来 302 | 303 | * Syntax: `scrapy fetch <url>` 304 | * 需要项目:_否_ 305 | 306 | 使用ScrapyDownloader下载给定的URL,并将内容写入标准输出。 307 | 308 | 这个命令的有趣之处在于它获取了 Spider 如何下载它的页面。例如,如果 Spider `USER_AGENT` 覆盖用户代理的属性,它将使用该属性。 309 | 310 | 所以这个命令可以用来“查看” Spider 如何获取特定的页面。 311 | 312 | 如果在项目之外使用,则不会应用特定的每 Spider 行为,它只会使用默认的scrapy下载器设置。 313 | 314 | 支持的选项: 315 | 316 | * `--spider=SPIDER` :绕过Spider自动检测并强制使用特定Spider 317 | * `--headers` :打印响应的HTTP头而不是响应的正文 318 | * `--no-redirect` :不遵循HTTP 3xx重定向(默认为遵循它们) 319 | 320 | 用法示例: 321 | 322 | ```py 323 | $ scrapy fetch --nolog http://www.example.com/some/page.html 324 | [ ... html content here ... ] 325 | 326 | $ scrapy fetch --nolog --headers http://www.example.com/ 327 | {'Accept-Ranges': ['bytes'], 328 | 'Age': ['1263 '], 329 | 'Connection': ['close '], 330 | 'Content-Length': ['596'], 331 | 'Content-Type': ['text/html; charset=UTF-8'], 332 | 'Date': ['Wed, 18 Aug 2010 23:59:46 GMT'], 333 | 'Etag': ['"573c1-254-48c9c87349680"'], 334 | 'Last-Modified': ['Fri, 30 Jul 2010 15:30:18 GMT'], 335 | 'Server': ['Apache/2.2.3 (CentOS)']} 336 | 337 | ``` 338 | 339 | ### 看法 340 | 341 | * Syntax: `scrapy view <url>` 342 | * 需要项目:_否_ 343 | 344 | 在浏览器中打开给定的URL,因为您的废 Spider 会“看到”它。有时候 Spider 看到的页面与普通用户不同,所以这可以用来检查 Spider “看到”什么,并确认它是你所期望的。 345 | 346 | 支持的选项: 347 | 348 | * `--spider=SPIDER` :绕过Spider自动检测并强制使用特定Spider 349 | * `--no-redirect` :不遵循HTTP 3xx重定向(默认为遵循它们) 350 | 351 | 使用实例: 352 | 353 | ```py 354 | $ scrapy view http://www.example.com/some/page.html 355 | [ ... browser starts ... ] 356 | 357 | ``` 358 | 359 | ### 壳 360 | 361 | * Syntax: `scrapy shell [url]` 362 | * 需要项目:_否_ 363 | 364 | 为给定的URL(如果给定)启动scrapy shell;如果没有给定URL,则为空。还支持Unix风格的本地文件路径,无论是相对于 `./` 或 `../` 前缀或绝对文件路径。见 [Scrapy shell](shell.html#topics-shell) 更多信息。 365 | 366 | 支持的选项: 367 | 368 | * `--spider=SPIDER` :绕过Spider自动检测并强制使用特定Spider 369 | * `-c code` :评估shell中的代码,打印结果并退出 370 | * `--no-redirect` :不遵循HTTP 3xx重定向(默认为遵循它们);这只影响在命令行上作为参数传递的URL;一旦进入shell, `fetch(url)` 默认情况下仍将遵循HTTP重定向。 371 | 372 | 使用实例: 373 | 374 | ```py 375 | $ scrapy shell http://www.example.com/some/page.html 376 | [ ... scrapy shell starts ... ] 377 | 378 | $ scrapy shell --nolog http://www.example.com/ -c '(response.status, response.url)' 379 | (200, 'http://www.example.com/') 380 | 381 | # shell follows HTTP redirects by default 382 | $ scrapy shell --nolog http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F -c '(response.status, response.url)' 383 | (200, 'http://example.com/') 384 | 385 | # you can disable this with --no-redirect 386 | # (only for the URL passed as command line argument) 387 | $ scrapy shell --no-redirect --nolog http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F -c '(response.status, response.url)' 388 | (302, 'http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F') 389 | 390 | ``` 391 | 392 | ### 解析 393 | 394 | * Syntax: `scrapy parse <url> [options]` 395 | * 需要项目:_是_ 396 | 397 | 获取给定的URL,并使用处理它的spider,使用 `--callback` 选项,或 `parse` 如果没有给出。 398 | 399 | 支持的选项: 400 | 401 | * `--spider=SPIDER` :绕过Spider自动检测并强制使用特定Spider 402 | * `--a NAME=VALUE` :set spider参数(可以重复) 403 | * `--callback` 或 `-c` :用作分析响应的回调的spider方法 404 | * `--meta` 或 `-m` :将传递给回调请求的附加请求元。这必须是有效的JSON字符串。示例:--meta='“foo”:“bar”' 405 | * `--pipelines` :通过管道处理项目 406 | * `--rules` 或 `-r` 使用 [`CrawlSpider`](spiders.html#scrapy.spiders.CrawlSpider "scrapy.spiders.CrawlSpider") 发现用于解析响应的回调(即spider方法)的规则 407 | * `--noitems` :不显示刮掉的项目 408 | * `--nolinks` :不显示提取的链接 409 | * `--nocolour` :避免使用Pygments对输出着色 410 | * `--depth` 或 `-d` :应递归执行请求的深度级别(默认值:1) 411 | * `--verbose` 或 `-v` :显示每个深度级别的信息 412 | 413 | 使用实例: 414 | 415 | ```py 416 | $ scrapy parse http://www.example.com/ -c parse_item 417 | [ ... scrapy log lines crawling example.com spider ... ] 418 | 419 | >>> STATUS DEPTH LEVEL 1 <<< 420 | # Scraped Items ------------------------------------------------------------ 421 | [{'name': 'Example item', 422 | 'category': 'Furniture', 423 | 'length': '12 cm'}] 424 | 425 | # Requests ----------------------------------------------------------------- 426 | [] 427 | 428 | ``` 429 | 430 | ### 设置 431 | 432 | * Syntax: `scrapy settings [options]` 433 | * 需要项目:_否_ 434 | 435 | 获取 Scrapy 设置的值。 436 | 437 | 如果在项目中使用,它将显示项目设置值,否则它将显示该设置的默认碎片值。 438 | 439 | 示例用法: 440 | 441 | ```py 442 | $ scrapy settings --get BOT_NAME 443 | scrapybot 444 | $ scrapy settings --get DOWNLOAD_DELAY 445 | 0 446 | 447 | ``` 448 | 449 | ### 运行 Spider 450 | 451 | * Syntax: `scrapy runspider <spider_file.py>` 452 | * 需要项目:_否_ 453 | 454 | 运行一个包含在python文件中的spider,而不必创建一个项目。 455 | 456 | 示例用法: 457 | 458 | ```py 459 | $ scrapy runspider myspider.py 460 | [ ... spider starts crawling ... ] 461 | 462 | ``` 463 | 464 | ### 版本 465 | 466 | * Syntax: `scrapy version [-v]` 467 | * 需要项目:_否_ 468 | 469 | 打印残缺版本。如果使用 `-v` 它还打印python、twisted和platform信息,这对bug报告很有用。 470 | 471 | ### 长凳 472 | 473 | 0.17 新版功能. 474 | 475 | * Syntax: `scrapy bench` 476 | * 需要项目:_否_ 477 | 478 | 运行一个快速基准测试。 [Benchmarking](benchmarking.html#benchmarking) . 479 | 480 | ## 自定义项目命令 481 | 482 | 还可以使用 [`COMMANDS_MODULE`](#std:setting-COMMANDS_MODULE) 设置。请参阅中的scrappy命令 [scrapy/commands](https://github.com/scrapy/scrapy/tree/master/scrapy/commands) 有关如何实现命令的示例。 483 | 484 | ### COMMANDS_MODULE 485 | 486 | 违约: `''` (空字符串) 487 | 488 | 用于查找自定义 Scrapy 命令的模块。这用于为您的Scrapy项目添加自定义命令。 489 | 490 | 例子:: 491 | 492 | ```py 493 | COMMANDS_MODULE = 'mybot.commands' 494 | 495 | ``` 496 | 497 | ### 通过setup.py入口点注册命令 498 | 499 | 注解 500 | 501 | 这是一个实验特性,小心使用。 502 | 503 | 还可以通过添加 `scrapy.commands` 库入口点中的节 `setup.py` 文件。 504 | 505 | 下面的示例添加了 `my_command` 命令: 506 | 507 | ```py 508 | from setuptools import setup, find_packages 509 | 510 | setup(name='scrapy-mymodule', 511 | entry_points={ 512 | 'scrapy.commands': [ 513 | 'my_command=my_scrapy_module.commands:MyCommand', 514 | ], 515 | }, 516 | ) 517 | 518 | ``` -------------------------------------------------------------------------------- /docs/img/6d09274a6a0eadb4fac81ff1bd508248.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/docs/img/6d09274a6a0eadb4fac81ff1bd508248.jpg -------------------------------------------------------------------------------- /docs/img/d3df2a33256732c3bb420ea930dbda9a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/docs/img/d3df2a33256732c3bb420ea930dbda9a.jpg -------------------------------------------------------------------------------- /docs/img/d74a68f3540ed16e6533632095e18fc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/docs/img/d74a68f3540ed16e6533632095e18fc1.jpg -------------------------------------------------------------------------------- /docs/img/ebf6f0b54b0530b158ca080658e3473d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/docs/img/ebf6f0b54b0530b158ca080658e3473d.jpg -------------------------------------------------------------------------------- /docs/img/fca494eacecdaeee595ae572e32d80d2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apachecn/scrapy-doc-zh/57adf043aa7a22ba40943d05c36086363e947ce4/docs/img/fca494eacecdaeee595ae572e32d80d2.jpg -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Scrapy 1.6文档 2 | 3 | 本文档包含您需要了解的有关Scrapy的所有信息。 4 | 5 | 6 | 7 | ## 获得帮助 8 | 9 | 遇到麻烦?我们想帮忙! 10 | 11 | - 试试[常见问题](https://docs.scrapy.org/en/latest/faq.html) - 它有一些常见问题的答案。 12 | - 寻找具体信息?尝试[索引](https://docs.scrapy.org/en/latest/genindex.html)或[模块索引](https://docs.scrapy.org/en/latest/py-modindex.html)。 13 | - [使用scrapy标签在StackOverflow中](https://stackoverflow.com/tags/scrapy)提问或搜索问题。 14 | - 在[Scrapy子板块](https://www.reddit.com/r/scrapy/)中询问或搜索问题。 15 | - 搜索[scrapy用户邮件列表](https://groups.google.com/forum/#!forum/scrapy-users)的档案问题。 16 | - 在[#scrapy IRC频道中](irc://irc.freenode.net/scrapy)提问。 17 | - 在我们的[issues跟踪器](https://github.com/scrapy/scrapy/issues)中提交Scrapy的bug。 18 | - 19 | 20 | ## 第一步 21 | 22 | [Scrapy初探](https://docs.scrapy.org/en/latest/intro/overview.html) 23 | 24 | ​ 了解Scrapy是什么以及它如何帮助您。 25 | 26 | [安装指南](https://docs.scrapy.org/en/latest/intro/install.html) 27 | 28 | ​ 在您的计算机上安装Scrapy。 29 | 30 | [Scrapy教程](https://docs.scrapy.org/en/latest/intro/tutorial.html) 31 | 32 | ​ 写下您的第一个Scrapy项目。 33 | 34 | [例子](https://docs.scrapy.org/en/latest/intro/examples.html) 35 | 36 | ​ 通过使用预设的Scrapy项目了解更多信息。 37 | 38 | 39 | 40 | ## 基本概念 41 | 42 | [命令行工具](https://docs.scrapy.org/en/latest/topics/commands.html) 43 | 44 | ​ 学习用于管理您的Scrapy项目的命令行工具。 45 | 46 | [爬虫(Spiders)](https://docs.scrapy.org/en/latest/topics/spiders.html) 47 | 48 | ​ 编写规则以抓取您的网站。 49 | 50 | [选择器(Selectors)](https://docs.scrapy.org/en/latest/topics/selectors.html) 51 | 52 | ​ 使用XPath从网页中提取数据。 53 | 54 | [Scrapy shell](https://docs.scrapy.org/en/latest/topics/shell.html) 55 | 56 | ​ 在交互式环境中测试您的提取代码。 57 | 58 | [Items](https://docs.scrapy.org/en/latest/topics/items.html) 59 | 60 | ​ 定义您要爬取的数据。 61 | 62 | [Item Loaders(加载器)](https://docs.scrapy.org/en/latest/topics/loaders.html) 63 | 64 | ​ 使用提取的数据填充您的Items。 65 | 66 | [Item Pipeline(管道)](https://docs.scrapy.org/en/latest/topics/item-pipeline.html) 67 | 68 | ​ 后期处理并存储您已爬取的数据。 69 | 70 | [原料输出](https://docs.scrapy.org/en/latest/topics/feed-exports.html) 71 | 72 | ​ 使用不同的格式和存储输出您的已爬取的数据。 73 | 74 | [请求和响应](https://docs.scrapy.org/en/latest/topics/request-response.html) 75 | 76 | ​ 理解用于表示HTTP请求和响应的类。 77 | 78 | [链接提取器](https://docs.scrapy.org/en/latest/topics/link-extractors.html) 79 | 80 | ​ 方便的类,用于从页面中提取关联链接。 81 | 82 | [设置](https://docs.scrapy.org/en/latest/topics/settings.html) 83 | 84 | ​ 学习如何配置Scrapy并查看所有[可用设置](https://docs.scrapy.org/en/latest/topics/settings.html#topics-settings-ref)。 85 | 86 | [异常](https://docs.scrapy.org/en/latest/topics/exceptions.html) 87 | 88 | ​ 查看所有可用的异常情况及其含义。 89 | 90 | 91 | 92 | ## 内置服务 93 | 94 | [日志记录(Logging)](https://docs.scrapy.org/en/latest/topics/logging.html) 95 | 96 | ​ 学习如何在Scrapy上使用Python的内置日志记录。 97 | 98 | [收集统计信息](https://docs.scrapy.org/en/latest/topics/stats.html) 99 | 100 | ​ 收集有关您正在爬取的爬虫的统计信息。 101 | 102 | [发送电子邮件](https://docs.scrapy.org/en/latest/topics/email.html) 103 | 104 | ​ 发生特定事件时发送电子邮件通知。 105 | 106 | [Telnet控制台](https://docs.scrapy.org/en/latest/topics/telnetconsole.html) 107 | 108 | ​ 使用内置的Python控制台检查正在运行的爬虫。 109 | 110 | [网络服务](https://docs.scrapy.org/en/latest/topics/webservice.html) 111 | 112 | ​ 使用Web服务监视和控制爬虫。 113 | 114 | 115 | 116 | ## 解决具体问题 117 | 118 | [经常问的问题](https://docs.scrapy.org/en/latest/faq.html) 119 | 120 | ​ 获得最常见问题的答案。 121 | 122 | [调试爬虫](https://docs.scrapy.org/en/latest/topics/debug.html) 123 | 124 | ​ 学习如何调试scrapy爬虫的常见问题。 125 | 126 | [爬虫合同](https://docs.scrapy.org/en/latest/topics/contracts.html) 127 | 128 | ​ 学习如何使用合同来测试您的爬虫。 129 | 130 | [常见做法](https://docs.scrapy.org/en/latest/topics/practices.html) 131 | 132 | ​ 熟悉一些Scrapy的常见做法。 133 | 134 | [通用爬虫](https://docs.scrapy.org/en/latest/topics/broad-crawls.html) 135 | 136 | ​ Tune Scrapy可以并行抓取大量域名。 137 | 138 | [使用浏览器的开发者工具进行抓取](https://docs.scrapy.org/en/latest/topics/developer-tools.html) 139 | 140 | ​ 学习如何使用浏览器的开发者工具。 141 | 142 | [调试内存溢出](https://docs.scrapy.org/en/latest/topics/leaks.html) 143 | 144 | ​ 学习如何查找和清除爬虫中的内存溢出。 145 | 146 | [下载和处理文件及图像](https://docs.scrapy.org/en/latest/topics/media-pipeline.html) 147 | 148 | ​ 下载与已爬取Items关联的文件和或图像。 149 | 150 | [部署爬虫](https://docs.scrapy.org/en/latest/topics/deploy.html) 151 | 152 | ​ 部署Scrapy爬虫并在远程服务器中运行它们。 153 | 154 | [AutoThrottle扩展](https://docs.scrapy.org/en/latest/topics/autothrottle.html) 155 | 156 | ​ 根据负载动态调整爬虫速率。 157 | 158 | [标杆管理](https://docs.scrapy.org/en/latest/topics/benchmarking.html) 159 | 160 | ​ 检查Scrapy如何在您的硬件上执行。 161 | 162 | [Jobs:暂停和恢复抓取](https://docs.scrapy.org/en/latest/topics/jobs.html) 163 | 164 | ​ 学习如何暂停和恢复大型爬虫的抓取。 165 | 166 | 167 | 168 | ## 扩展Scrapy 169 | 170 | [架构概述](https://docs.scrapy.org/en/latest/topics/architecture.html) 171 | 172 | ​ 了解Scrapy架构。 173 | 174 | [下载中间件](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html) 175 | 176 | ​ 自定义页面的请求和下载。 177 | 178 | [爬虫中间件](https://docs.scrapy.org/en/latest/topics/spider-middleware.html) 179 | 180 | ​ 自定义您的爬虫的输入和输出。 181 | 182 | [扩展](https://docs.scrapy.org/en/latest/topics/extensions.html) 183 | 184 | ​ 使用您的自定义功能扩展Scrapy 185 | 186 | [核心API](https://docs.scrapy.org/en/latest/topics/api.html) 187 | 188 | ​ 在扩展和中间件上使用它来扩展Scrapy功能 189 | 190 | [信号](https://docs.scrapy.org/en/latest/topics/signals.html) 191 | 192 | ​ 查看所有可用信号以及如何使用它们。 193 | 194 | [Item导出](https://docs.scrapy.org/en/latest/topics/exporters.html) 195 | 196 | ​ 快速将您已爬取的items导出到文件(XML,CSV等)。 197 | 198 | 199 | 200 | ## 其他 201 | 202 | [发行说明](https://docs.scrapy.org/en/latest/news.html) 203 | 204 | ​ 查看最近Scrapy版本中的变化。 205 | 206 | [为Scrapy做贡献](https://docs.scrapy.org/en/latest/contributing.html) 207 | 208 | ​ 学习如何为Scrapy项目做出贡献。 209 | 210 | [版本控制和API稳定性](https://docs.scrapy.org/en/latest/versioning.html) 211 | 212 | ​ 了解Scrapy版本控制和API稳定性。 213 | 214 | 215 | 216 | [下一个 ](https://docs.scrapy.org/en/latest/intro/overview.html) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
now loading...
21 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | git add -A 2 | git commit -am "$(date "+%Y-%m-%d %H:%M:%S")" 3 | git push --------------------------------------------------------------------------------