week11🎃11月09日
目录

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 名称