week1111月09日
目录
1.整个工作流程编辑
2.名词解释
(1)引擎engine
(2)调度器scheduler
(3)下载器downloader
(4)爬虫spider
(5)管道pipeline
3.Scrapy实例
(1)创建项目
(2)进入目录
(3)查看结构
4.xpath语法
4.1路径表达式
4.1.1实例
4.2谓语(predicates)
4.2.1实例
4.3属性查询
4.4内容查询
4.5模糊查询
5.程序代码
6.自定义数据传输结构item
7.修改pipeline中的代码
8.Scrapy总结
1.爬虫中起始的url构造成request对象,并传递给调度器;
2.‘引擎’从‘调度器’中获取到request对象,然后交给‘下载器’;
3.由’下载器‘来获取到页面源代码,并封装成response对象,并回馈给’引擎‘;
4.‘引擎’将获取到的response对象传递给‘spider’,由‘spider’对数据进行解析(parse),并回馈给‘引擎’;
5.’引擎‘将数据传递给pipeline进行数据持久化保存或进一步的数据处理;
6.在此期间如果spider中提取到的并不是数据.而是子页面url.可以进一步提交给调度器,进而重复步骤2;
Scrapy的核心,衔接所有模块,梳理数据流程。
本质上,调度器可以看成是一个集合和队列,里面存放着一堆我们即将要发送的请求,可以看成是一个url的容器,它决定了下一步要去爬取哪一个url,通常我们这里可以对url进行去重操作。
它的本质就是用来发动请求的一个模块,可以把它理解成是一个requests.get()的功能,只不过返回的是一个response对象。
我们要写的第一个部分的内容,负责解析下载器返回的response对象,从中提取到我们需要的数据。
我们要写的第二个部分的内容,主要负责数据的存储和各种持久化操作。
scrapy startproject 项目名称
scrapy startproject mySpider_2
cd mySpider_2
ls
cd mySpider_2
创建好项目后,我们可以在pycharm里观察到scrapy帮我们创建了一个文件夹,里面的目录结构如下:
tree
XPath是在XML文档中查找信息的语言。XPath用于在XML文档中通过元素和属性进行导航。
表达式 | 描述 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
./ | 当前节点再次进行xpath |
@ | 选取属性 |
在下面的表格中,列出了一些路径表达式以及其结果:
路径表达式 | 结果 |
/html | 选取根元素bookstore,注释:假如路径起始于正斜杠(/),则此路径始终代表到某元素的绝对路径! |
//li | 选取所有li子元素,而不管它们在文档中的位置。 |
//ul/li | 选取属于ul元素的后代的所有li元素,而不管它们位于ul之下的什么位置。 |
节点对象.xpath('./div') | 选择当前节点对象里面的第一个div节点 |
//@href | 选取名为href的所有属性 |
谓语用来查找某个特定的节点或者包含某个指定的值的节点 。
谓语被嵌在方括号中。
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 | 结果 |
/ul/li[1] | 选取属于ul子元素的第一个li元素 |
/ul/li[last()] | 选取属于ul子元素的最后一个li元素 |
/ul/li[last()-1] | 选取属于ul子元素的倒数第二个li元素 |
//ul/li[position()<3] | 选取最前面的两个属于ul元素的子元素的li元素 |
//a[@title] | 选取所有拥有名为title的属性的a元素 |
//a[@title='xx'] | 选取所有a元素,且这些元素拥有值为xx的title属性 |
//a[@title>10] > < >= <= ! = | 选取a元素的所有title元素,且其中的title元素的值须大于10 |
·查询所有id属性中包含以he开头的div标签
//div[starts-with(@id,"he")]
·查询所有id属性等于maincontent的div标签
//div[@id = "maincontent"]
·查找所有div标签下的直接子节点h1的内容
//div/h1/text()
·属性值获取
//div/a/@href 获取a里面的href属性值
·获取所有
//*获取所有
//*[@class="xx"]#获取所有class为xx的标签
·获取节点内容转换成字符串
c = tree.xpath('//li/a')[0]
result = etree.tostring(c.encoding='uff-8')
print(result.decode('UTF-8')
·查找所有的class属性
//@class
·//@attrName
//li[@name="xx"]text() #获取li标签name为xx的里面的文本内容
·获取第几个标签 索引从1开始
tree.xpath('//li[1]/a/text()') #获取第一个
tree.xpath('//li[last()]/a/text()') #获取最后一个
tree.xpath('//[last()-1]/a/text()') #获取倒数第二个
import scrapy
class YouxiSpider(scrapy.Spider):
name = 'youxi' #该名字非常关键,我们在启动该爬虫的时候需要这个名字
allowed_domains = ['4399.com'] #爬虫抓取的域
start_urls = ['http://www.4399.com/flash/'] #起始页
def parse(self,response,**kwargs):
#response.txt #页面源代码
#response.xpath #通过xpath方式提取
#response.css() #通过css方式提取
#response.json() #提取json数据
#用我们最熟悉的方式:xpath提取游戏名称、游戏类别、发布时间等信息
li_list = response.xpath("//ul@class='n-game cf//li")
for li in li_list:
name = li.xpath("./a/b/text()").extract_first()
category = li.xpath("./em/a/text()").extract_first()
date = li.xpath("./em/text()").extract_first()
dic = {
"name":name,
"category":category;
"date":date}
item = Myspider2Item()
item["name"] = name
item["category"] = category
item["date"] = date
yield item
#将提取到的数据提交到管道内
#注意,这里只能返回request对象、字典、item数据,or None
#yield dic
在上述案例中,我们使用字典作为数据传递的载体,但是如果数据量非常大,由于字典的key是随意创建的,极易出现问题,此时再用字典就不合适了。Scrapy中提供item作为数据格式的声明位置,我们可以在items.py文件提前定义好该爬虫在进行数据传输时的数据格式,然后再写代码的时候就有了数据名称的依据。
class Myspider2Pipeline
def process_item(self, item, spider)
print(item)
return item
注意:spider返回的内容只能是字典、requests对象、item数据或者None,其他内容一律报错。
运行爬虫
scrapy crawl 爬虫名字
至此,我们对scrapy有了一个非常初步的了解和使用,scrapy框架的使用流程:
(1)创建爬虫项目
scrapy startproject xxx
(2)进入项目目录
cd xxx
(3)创建爬虫
scrapy genspider 名称 抓取域
(4)编写item.py 文件,定义好数据item;
(5)修改spider中的parse方法.,对返回的响应response对象进行解析,返回item;
(6)在pipeline中对数据进行保存工作;
(7)修改settings . py文件,将pipeline设置为生效,并设置好优先级;
(8)启动爬虫
scrapy crawl 名称