Python爬虫最后的学习-Scrapy框架,持续更新
这是关于Scrapy框架学习中所有坑和所思所想
学习态度:“你不会是第一个遇到问题的人,也不会是最后一个”
首先保留了Markdown的教学,以保证我每次记录时都能学习它的使用方法,并且这个博客内容持续更新至我学习完Scrapy框架内容结束。(优快云编辑器已经帮我完成了)
这是我的学习材料:Scrapy框架学习资料,需要的朋友留言
前言
在学习Scrapy之前我先学习了PySpider,直观来说,后者轻便,可视化;前者说实话有点复杂,需要一点点去理清楚。
根据学习材料一步一步来。
正文
Base 框架安装
在Windows环境下安装Scrapy是很麻烦的,首先要通过pip安装其他需要库,最后再安装Scrapy。如果缺少一个库,都有可能导致Scrapy无法正常使用。所以在Windows下推荐是使用Anaconda进行安装,只需要一行简单的代码即可。
>> conda install scrapy
在安装库之前我将pip升级到了19.1.1,没想到居然报错了。
报错如下:
Traceback (most recent call last):
File “f:\python\lib\runpy.py”, line 170, in _run_module_as_main
“main”, mod_spec)
File “f:\python\lib\runpy.py”, line 85, in run_code
exec(code, run_globals)
File "F:\python\Scripts\pip.exe_main.py", line 5, in
ImportError: No module named ‘pip’
我在论坛发现了解决办法如下:参考地址
重新安装pip,在cmd中运行命令如下:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py --force-reinstall
通过反复的尝试,pip install Twisted 会出现问题,只好通过下载好的Twisted安装,pip install ‘路径’。安装时一定要注意与python版本相对应不然会出现下面的报错。
Base 基本使用
首先在控制台输入scrapy(确保在系统path里),出现
说明scrapy已经成功安装好了。
再通过命令行
scrapy genspider project_name + url
建立一个新的Scrapy项目,会自动生成一个完整的Scrapy爬虫结构。基本代码都写在与项目同名的文件夹下的 spider > project_name.py 的parse方法里。同时,会生成Scrapy.cfg文件,保存着项目的基本变量。
def parse(self,response):
any = response.css('')
for n in any:
item_1 = n.css('.text::text').extract_first() # 提取出text中的第一个
item_2 = n.css('.text::text').extract() # 提取所有text内容
# 如果编辑了items还需要初始化一下Item
# item = Project_nameItem()
# item['item_1'] = item_1
# yield item
next = response.css(' a::attr(herf)').extract_first() # 继续翻页
# url = response.urljoin(next) # 拼接url的方法
yield scrapy.Request(url=next, callback=self.parse)
parse方法的写法比较特别也比较正常,有点类似于PyQuery的写法,不过在提取标签内容的时候有其独特性。
scrapy crawl project_name -o file_name.type
对爬取的内容的数据收集要先在Items中编辑,数据的输出在Pipelines中编辑。简单的数据保存可以直接通过命令行就可以根据你所指定的文件后缀保存数据。
另外,在Settings文件中保存了当前项目的变量和功能的开关,需要时要注意开启,有些功能涉及编号,也就是优先级,数字小的优先级更高。
Base 命令行使用
所有的操作都是参照Scrapy官方文档
命令分为两类全局命令和项目命令,在使用全局命令时在项目文件夹外输入命令,而使用项目命令时就需要进入相应的项目文件目录下输入命令。
就创建一个Scrapy项目来说,我们可以使用genspider和startproject两个命令,他们的区别在于
- startproject Syntax: scrapy startproject (project_name) [project_dir]
- genspider Syntax: scrapy genspider [-t template] (name)(domain)
- 前者可以指定创建项目的目录。
- 后者可以创建预定的模板。(不过对于我这个小白来说,还不知道模板能带来多大的便利)
另外三个非常好用的命令,
‘‘fetch’’ Supported options:
- –spider=SPIDER: bypass spider autodetection and force use of specific spider
- –headers: print the response’s HTTP headers instead of the response’s body
- –no-redirect: do not follow HTTP 3xx redirects1 (default is to follow them)
返回抓取url的html
‘‘view’’ Supported options:
- –spider=SPIDER: bypass spider autodetection and force use of specific spider
- –no-redirect: do not follow HTTP 3xx redirects (default is to follow them)
返回抓取url的html并保存为文件再用Browser打开
“shell” 交互式命令行模式
- url
其他剩下的命令的作用都是简单易懂看一下文档就知道了,就不多说了。
//进入目录
>cd
//返回上级目录
>cd..
//树状图显示当前文件夹结构
>tree
//帮助
>-h
//最后补充一下,Windows下命令行操作的基本命令,如果不懂可以-h还会出现中文解释,非常友好
Base 选择器使用
Scrapy内置了三个选择器方法
- CSS(response.selector.css | response.css)
- XPath(response.selector.xpath | response.xpath)
- 正则表达式(response.selector.re | response.re)
可以根据个人喜好和使用习惯选择其中任何一个选择器进行匹配,不过所有的返回结果都是一个Scrapy内置的一个Selector类,因此可以进行迭代的选择。另外,CSS选择器有一些特殊的操作(双引号和extract)。
- response.css('a[href=xxx]’) 指选择a标签中href=xxx的标签
- response.css(‘a::text’) 选择a标签中的文本内容
- response.css(‘a::attr(href)’) 选择a标签中的href属性
最后因为选择器返回的结果都是一个Selector对象, 所以要获取到其中的信息要使用extract方法或者extract_first。
Spiders 用法
在Spiders中包括我们需要抓取的url以及url的解析规则。
记录有几个关键的函数和变量:
函数、变量 | 格式 | 作用 | 参数 |
---|---|---|---|
“start_urls” | 列表或者字符串 | 首先进入的url | - |
“custom_setting” | 字典 | 覆盖项目的全局设置 | - |
”start_requests()“ | return [scrapy.Request()] | 复写scrapy启动时调用的第一个请求 | url, callback,meta={},method, |
“parse” | 爬取规则 | 解析所需内容 | response |
在实际使用中,我发现start_requests中url参数只能以字符串的格式传入,而在Spider类中的start_urls变量又是可以使用列表格式的。当我复写其并且想传入多个url时,出现了bug,真是头疼。
源码:
def start_requests(self):
cls = self.__class__
if method_is_overridden(cls, Spider, 'make_requests_from_url'):
warnings.warn(
"Spider.make_requests_from_url method is deprecated; it "
"won't be called in future Scrapy releases. Please "
"override Spider.start_requests method instead (see %s.%s)." % (
cls.__module__, cls.__name__
),
)
for url in self.start_urls:
yield self.make_requests_from_url(url)
else:
for url in self.start_urls:
yield Request(url, dont_filter=True)
问题解决:
查看源码后,这个问题就变得相当简单了,之所以"start_urls"先进行遍历,再进行请求,并且在源码中使用的请求类是scrapy.http中的Request类,那么之后可以直接引入这个类,编写更灵活的请求。
函数、变量 | 格式 | 作用 | 参数 |
---|---|---|---|
Request() | yield Request() | 请求url | url,callback,dont_filter, meta={} |
To Be Continue