如果对xpath语法比较了解,可以只阅读总结部分
scrapy简介
异步和非阻塞的区别
scrapy爬虫的流程
各模块的作用
入门
创建项目
scrapy startproject myspider
myspider是项目名
生成一个爬虫
scrapy genspider itcast "itcast.cn"
参数含义:itcast是爬虫名字,itcast.cn是爬取的范围,一般是域名
执行命令后,会在myspider/spiders
生成itcast.py
文件
myspider/spiders/itcast.py
import scrapy
class ItcastSpider(scrapy.Spider):
name = 'itcast'
# 允许爬取范围
allowed_domains = ['itcast.cn']
# 最开始请求url地址
start_urls = ['http://itcast.cn/']
def parse(self, response):
pass
提取数据
完善spider,使用xpath等办法
保存数据
pipeline中保存数据
启动爬虫
cd 项目根目录
scrapy crawl 爬虫名字
目录结构
|____myspider
| |____spiders
| | |______init__.py
| | |______pycache__
| | | |______init__.cpython-37.pyc
| | |____itcast.py
| |______init__.py
| |______pycache__
| | |____settings.cpython-37.pyc
| | |______init__.cpython-37.pyc
| |____middlewares.py
| |____settings.py
| |____items.py
| |____pipelines.py
|____scrapy.cfg
scrapy.cfg
[settings]
# 项目配置文件settings.py
default = myspider.settings
[deploy]
# 代码发布
#url = http://localhost:6800/
project = myspider
settings.py
- 设置日志级别
# 日志等级
LOG_LEVEL = "WARNING"
LOG_LEVEL = "WARNING"
表示warning以下的错误不打印日志
xpath语法
基本语法
- 选取节点
路径表达式 | 结果 |
---|---|
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径 |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置 |
//@lang | 选取名为 lang 的所有属性,获得lang属性的值 |
- 谓语(Predicates)
查找某个特定的节点或者包含某个指定的值的节点。谓语嵌在方括号中
路径表达式 | 结果 |
---|---|
. | 当前元素 |
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素 |
/bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素 |
//title[@lang='eng'] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00 |
/bookstore/book[price>35.00]//title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00 |
./book/following-sibling::price[1] | 获取book节点的第一个price兄弟节点 |
注意:以下使用场景
<div class='a b'>test</div>
如果是用
xpath('//div[@class="a"]')
会取不到里面的值,可以用如下的表达式:
xpath('//div[contains(@class,"a")]') #它会取得所有class包含a的元素
同时包含多个类的情况
xpath('//div[contains(@class,"a") and contains(@class,"b")]') #它会取class同时有a和b的元素
不要在任何选择器中出现tbody标签,可以阅读这篇文章https://hexfox.com/p/having-trouble-extracting-the-tbody-element-during-my-web-scrape/,了解为什么
Xpath选择器://table[@class="some_class"]/tbody/tr=> //table[@class="some_class"]/tr。
CSS选择器:table.some_class>tbody>tr=> table.some_class>tr
//
这类只能在第一次选择时使用,以/
开头表示从任意目录开始找
- 取值
表达式 | 示例 | 结果 |
---|---|---|
text() | /bookstore/book[1]/text() | 选取属于 bookstore 子元素的第一个 book 元素,提取其文本 |
text() | //bookstore/a[text()='abc'] | 选取bookstrore子元素中文本为abc的a标签 |
extract() | response.xpath("//div[@class='tea_con']//h3/text()").extract() | 返回一个标签列表,不加extract()返回的是选择器 |
extract_first() | item['title'] = li.xpath(".//h4/text()").extract_first() | 返回一个标签,不加extract_first()返回的是选择器 |
@src | //img/@src | 返回所有图片的src |
语法示例
- 路径选择 //
//div[@class='tea_con']//li
选取带有class
属性,且值为tea_con
的所有div
元素下的所有li
元素
- extract()
def parse(self, response):
ret1 = response.xpath("//div[@class='tea_con']//h3/text()").extract()
print(ret1)
extract()返回一个列表,里面是提取的元素
- extract_first()
def parse(self, response):
li_list = response.xpath("//div[@class='tea_con']//li")
for li in li_list:
item = {}
item['name'] = li.xpath(".//h3/text()").extract()[0]
item['title'] = li.xpath(".//h4/text()").extract()[0]
#item['title'] = li.xpath(".//h4/text()").extract_first()
print(item)
extract()[0]表示选择符合条件的第一个元素,该方法如果数组为空会报错,而extract_first()在数组为空时会返回None,不会报错
使用场景
当只需要列表项中的数据的第一个结果时用extract_first()
完整案例
- 提取数据
itcast.py
class ItcastSpider(scrapy.Spider):
name = 'itcast'
# 允许爬取范围
allowed_domains = ['itcast.cn']
# 最开始请求url地址
start_urls = ['http://www.itcast.cn/channel/teacher.shtml']
# //表示从匹配的当前节点
def parse(self, response):
# ret1 = response.xpath("//div[@class='tea_con']//h3/text()").extract()
# print(ret1)
# scrapy返回的不是普通的列表,可以使用extract()提取列表中每项元素
li_list = response.xpath("//div[@class='tea_con']//li")
for li in li_list:
item = {}
item['name'] = li.xpath(".//h3/text()").extract_first()
item['title'] = li.xpath(".//h4/text()").extract_first()
yield item
最后yeild将提取的每一项交给pipiline处理
- 开启pipeline
settings.py
ITEM_PIPELINES = {
'myspider.pipelines.MyspiderPipeline': 300,
}
myspider.pipelines.MyspiderPipeline
表示项目名.文件名.类名
300
是优先级,数字越小,优先级越高
注意:
- 只有开启pipeline,才能在(pipelines.py)中对数据进行处理
- 优先级较高的pipeline必须把数据return回去,否则后面的pipeline不能接收到数据