1、scrapy python的爬虫框架,非常出名,我们此处学用法,实现功能即可。有兴趣可以下载源码、理解,底层使用了多进程、多线程、队列等技术。
2、安装:pip installscrapy
注意如果出错:
building 'twisted.test.raiser' extension
error: Microsoft Visual C++ 14.0 is required. Get it with"Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
解决方案:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
下载twisted对应版本的whl文件(如我的Twisted-17.5.0-cp36-cp36m-win_amd64.whl),cp后面是python版本,amd64代表64位,运行命令:
pip install C:\Users\Downloads\Twisted-17.5.0-cp36-cp36m-win_amd64.whl
3、框架的介绍:
由5部分组成
① 引擎
② 下载器(负责下载)、
③ spiders(爬虫文件)、
④ 调度器(调度的、爬虫、给你一个url、爬完这个需要再去提取指定的url接着爬、调度器统一分发、生成一个请求对象,看让谁发送这个请求对象)
⑤ 管道(pipeline)
我们的代码写到spider与管道中,spider里面实现内容解析、链接提取(比如爬取内容、不只爬取第一页内容,每页链接不一样);管道:决定数据是保存到mysql、文件、还是mongodb中。
4、scrapy工作原理:
见图片:
先给个起始url,在spiders代码里放着,引擎会将起始url要过来,不做实际的工作,扔给调度器,调度器有个队列,负责调度,如果需要下载,出队给引擎,引擎不负责下载,扔给下载器,从互联网把数据下载下来,会将数据再扔给引擎,引擎将数据给spiders,spiders里面有解析内容的代码,解析时候会有你想要的数据,存放到一个字典中,(不仅有数据。还会有其他的url)总之,解析完之后有两种结果,url与数据,如果是数据,扔给引擎,引擎扔给管道,管道处理数据,存到哪里?mysql?mongodb?如果是url,就会给调度器,再重复上述的步骤。
注意:
爬虫核心:都在spiders里面;
其他的 扔出去系统都会给处理的;
管道里面也是需要自己写的;
调度器里面也不需要自行编写。出队是系统决定的;
5、scrpy简单使用
(1)创建项目:
在当前文件夹 打开超级终端
scrapy startproject firstblood
(scrapy路径、还有包都在此路径放着,你可以开启指令开始爬虫 cd进来,然后看下文)
*认识目录结构:(*为你需要打交道的文件)
firstblood
firstblood(真正的项目文件)
__pycache__(缓存文件)
spiders(爬虫文件存放的位置)
__pycache__
__init__.py
lala.py(爬虫文件、涉及文件的解析*)
__int__.py(包的标志)
items.py(定义数据结构的的地方*)
middlewares.py(中间件)
pipelines.py(管道文件*)
settings.py(配置文件*)
scrapy.cfg(不用管)
(2)生成爬虫文件
cd firstblood
scrapy genspider qiubaiwww.qiushibaike.com
qiubai:(爬虫的名字)
www.qiushibaike.com:(爬取的域名)
会生成一个qiubai.py文件:
# -*- coding: utf-8 -*-
import scrapy
class QiubaiSpider(scrapy.Spider):
# 爬虫的名字
name = 'qiubai'
# 允许的域名, 是一个列表,里面可以放多个,一般都做限制
allowed_domains = ['www.qiushibaike.com', 'www.baidu.com']
# 起始url,是一个列表
start_urls = ['https://www.qiushibaike.com/']
# 解析函数,重写这个方法,发送请求之后,响应来了就会调用这个方法,函数有一个参数response就是响应内容,该函数对返回值有一个要求,必须返回可迭代对象
def parse(self, response):
pass
class QiubaiSpider()
1爬虫的名字
2允许的域名(多了一个限制,只爬取此域名下,不限制的话就是全爬取。如果域名比较多,此是一个列表,加逗号,往后接着写域名)
3起始url(从哪儿开始爬取)
4 def parse
(解析函数,写解析的代码,发送的请求,响应过来之后,就在这里解析,重写这个方法,方法名不能改变,在这个方法中,响应就是传个参数,response(就是响应内容),会自动调用,不用再手动写,该函数对返回值有一个要求,就是返回可迭代对象)
*认识response对象
程序是如何跑起来的:
指令模式:
cd firstblood
firstblood
cd spiders
scrpycrawl qiubai
运行之后、有三处错误:
1.win32,注意版本
2.取消遵从robots协议 settings.py 在第22行
3.U-A头部信息改一下,粘个headers在后面。在第19行
print(response.text)字符串类型
print(response.body)打印的字节类型
xpath():scrapy内部已经集成了xpath,直接使用即可,但是与原生的稍微有不同,后续会展示。
(3)执行输出指定格式
scrapycrawl qiubai -o qiubai.json
scrapycrawl qiubai -o qiubai.xml
scrapycrawl qiubai -o qiubai.csv
【注】你输出为csv的时候,中间估计有空行,自己百度一下解决掉即可
1、scrapy shell是什么?
是一个调试工具,常用来调试xpath对不对。
2、安装依赖:pip installipython
更加智能的交互环境可以通过tab提示内容
终端下任意位置,输入如下指令:
scrapyshell 域名
3、属性
response.url 请求的url
response.body字节类型
response.text
response.status响应状态码
response.headers响应头
方法:xpath()提取出来的都是selector对象,需要进行extract()一下,然后再提取出来字符串
css():根据选择器进行获取指定的内容
示例:
ret=response.css('#content-left>div?.authorimg::attr(src)')
ret=response.css('#content-left'>div>.authorh2::text')
ret[0].extract()
selector对象
是scrapy自己封装的一个对象,不论你上面通过xpath还是css,获取到的都是这个对象
xpath()
css()
extract():将对象直接转化为字符串
extract_first():功能就等同于
extract_first()==[0].extract()=extract()[0]
如果xpath或者css写错了,返回一个空列表,通过后两种方式就会报错,但是通过extract_first()获取,就会获取none
item对象
爬取数据的时候,第一步就是要定义数据结构,在item.py中定义,通过这个类创建的对象十分特殊,类似字典,字典怎么用,它就怎么用,这个对象可以快速地转换为字典
回到ipthon输入:
classPerson(scrapy.Item)(继承这个类)
name=scray.Field()
age=scray.Field()
p=Person()(创建一个对象)
p['name']='goudan'(赋值)
p['age']=20
p['name']打印
p['age']
type(p)
d=dict(p)(转化为字典)
1、yield是什么意思?
deftest():
lt=[]
forx in range(1,11):
lt.append(x)
returnlt
如果写100个,1000个,一下生成1000个,写到列表中,都会显示出来,这样资源浪费,所以就引入了生成器。生成器,不是保存的数据,而是保存一个算法,用到的时候,直接调用,再给你生成。
def demo():
forx in range(1,11):
yieldx
a=demo()
print(a)
此时demo就不再是个函数 a=demo() print(a)就是一个生成器
print(next(a))取出第一个数据
print(next(a))
print(next(a))
print(next(a))
print(next(a))
....
print(next(a))到第11个再取就会报错。
也可以遍历:
for x in a:
print(x)
defdemo():
for x in range(1,11):
yield x
print'嘻嘻嘻'
yield '哈哈哈'
如果是print(next(a)),则只会打印一个1,嘻嘻嘻不会打印,只有打印下一个的时候,嘻嘻嘻才会打印
函数中可以出现yield,证明这个函数是生成器,可以有多个yield
....
print(next(a))到第11个再取就会报错。