文章链接
编号 | 分类 | 文章及链接 | 介绍 | 作者 | 来源分类 | 撰写日期 | 收录日期 |
---|---|---|---|---|---|---|---|
F1 | 框架 | Python有哪些常见的、好用的爬虫框架? | 知乎 | 2020-12-08 | 2022-08-07 | ||
I1 | 安装 | 从原理到实战,一份详实的 Scrapy 爬虫教程 | 简洁明了Scraph从安装到开发出第一个实用爬虫例子。好文。 | 开发者社区 | 腾讯云 | 2021-08-05 | 2022-08-08 |
B1 | 基础 | Running multiple spiders in the same process | 介绍Scraph如何并行或者按顺序启动多个爬虫 | 官网文档 | scrapy官网 | 2020-12-03 | 2022-08-08 |
T1 | 技巧 | scrapy头部修改详解 | 介绍Scraph的四种请求header修改方式 | 周少钦 | CSDN博客 | 2020-12-03 | 2022-08-08 |
T2 | 工具 | 爬虫必备工具,掌握它就解决了一半的问题 | 介绍了chrome开发者工具的用法,很实用 | Crossin | 知乎 | 2018-07-09 | 2022-08-08 |
文章目录
前言
最近用了三天的零碎时间写了一个GEM的NFT稀有度排名的爬虫。从框架选择到打包好进入正式服务器运行,踩坑填坑费了一些周折,特此记录。
1. 框架选择
相信初次接触爬虫的人都存在一个选什么框架最合适的问题,我也不例外。参考了知乎的这篇文章,Python有哪些常见的、好用的爬虫框架?。 诸多回答中不约而同提到了scraph, 而且也提到scraph上手简单。有知乎回答者提到使用“requests + beautifulsoup4 + lxml 完美组合” 或者“gevent, requests, 正则, pyv8,动态静态全吃” 对于致力于爬虫开发者来讲,肯定是更好的选择。对于我这个偶尔使用者来讲,为了快速实现功能,还是定Scraph框架吧。
2. Scrapy安装
从原理到实战,一份详实的 Scrapy 爬虫教程简洁明了Scraph从安装到开发出第一个实用爬虫例子,参考此文即可安装好。
3. Chrome/Postman查找验证爬虫参数
正确的参数是能爬到数据的关键一环。爬虫必备工具,掌握它就解决了一半的问题介绍了chrome开发者工具查找参数的办法。很实用。
Postman可以模拟发布请求,检查参数是是否正确或者必要,是找参数的好助手。
4. 编写逻辑代码
Scraph安装好,通过集成IDE里面的Scraph向导可以生成框架需要的源代码文件。
上图是标准文件夹结构及标准的撰写爬虫逻辑的代码文件。
在spider下面的xxx.py里提交网络请求(start_requests())以及解析网络返回结果(parse(self, response))。
在items.py 里面定义解析结果的数据项。
在pipelines.py里面对根据解析生成的数据做最后的加工处理(process_item()),通常是将结果写入数据库,打印日志什么的。
在settings.py里面配置爬虫参数。
5. 打包发布及运行
最常用的打包工具是pyinstaller. 按照pyinstaller 默认的方式打包到一个目录下。打包到文件的话(使用-F参数)会出现找不到设置的情况。
pyinstaller start.py
但是下面这种启动方式,打包运行会出错。
# 脚本执行模式(不适合打包启动) gem是我的爬虫名字
cmdline.execute('scrapy crawl gem'.split())
5.1 启动方式使用CrawlerProcess替代cmdline.execute(‘scrapy crawl XXX’.split())
需要对启动文件做一个修改。适合打包运行的写法:
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from nftRankSpider.spiders.gem import GemSpider
from nftRankSpider.pipelines import NftrankspiderPipeline
from nftRankSpider.items import GemNftRankItem
import nftRankSpider.settings
def run_mycrawler():
process = CrawlerProcess(get_project_settings())
# crawl方法的启动参数为spider名称
process.crawl(GemSpider)
process.start()
if __name__ == '__main__':
run_mycrawler()
Tips
注意,imoprt的最后三项(NftrankspiderPipeline, GemNftRankItem, nftRankSpider.settings)虽然没有直接用到,但不做import的话,运行时会出现找不到某些模块的错误。import的最后四项对应的内容,都是框架生成可以自己修改代码的类或者代码块。
5.2 Spider中添加warn_on_generator_with_return_value_stub方法并执行
较高版本的scrapy在pyinstaller打包后,如果源代码中有yield方法,会有运行报错:scrapy OSError: could not get source code
在spider(gem.py) 最后加入下面的四行语句可以解决这个打包问题(注意加入两行import语句) 参考Scrapy Pyinstaller OSError: could not get source code / twisted.internet.defer._DefGen_Return:
import scrapy.utils.misc
import scrapy.core.scraper
class GemSpider(scrapy.Spider):
name = 'gem'
allowed_domains = ['beta.gem.xyz', 'api-1.gemlabs.xyz', 'api-2.gemlabs.xyz', 'api-5.gemlabs.xyz'] # 可以修改
def start_requests(self):
...
def parse(self, response):
...
def warn_on_generator_with_return_value_stub(spider, callable):
pass
scrapy.utils.misc.warn_on_generator_with_return_value = warn_on_generator_with_return_value_stub
scrapy.core.scraper.warn_on_generator_with_return_value = warn_on_generator_with_return_value_stub
6 在同一个进程里面并行/串行启动多个爬虫
参考scrapy官网的这篇文章Running multiple spiders in the same process
6.1 并行启动多个爬虫
参考下面的代码,使用CrawlerProcess
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
class MySpider1(scrapy.Spider):
# Your first spider definition
...
class MySpider2(scrapy.Spider):
# Your second spider definition
...
settings = get_project_settings()
process = CrawlerProcess(settings)
process.crawl(MySpider1)
process.crawl(MySpider2)
process.start() # the script will block here until all crawling jobs are finished
或者使用CrawlerRunner
import scrapy
from twisted.internet import reactor
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
from scrapy.utils.project import get_project_settings
class MySpider1(scrapy.Spider):
# Your first spider definition
...
class MySpider2(scrapy.Spider):
# Your second spider definition
...
configure_logging()
settings = get_project_settings()
runner = CrawlerRunner(settings)
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d = runner.join()
d.addBoth(lambda _: reactor.stop())
reactor.run() # the script will block here until all crawling jobs are finished
6.2 按顺序执行多个爬虫(尚待验证)
from twisted.internet import reactor, defer
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
from scrapy.utils.project import get_project_settings
class MySpider1(scrapy.Spider):
# Your first spider definition
...
class MySpider2(scrapy.Spider):
# Your second spider definition
...
configure_logging()
settings = get_project_settings()
runner = CrawlerRunner(settings)
@defer.inlineCallbacks
def crawl():
yield runner.crawl(MySpider1)
yield runner.crawl(MySpider2)
reactor.stop()
crawl()
reactor.run() # the script will block here until the last crawl call is finished