正则表达式(特殊字符)
chrome控制台搜索:$x('//*[@id="body_container"]/div[3]/div[2]/div/div/a[1]/@href')
^ 开头 '^b.*'----以b开头的任意字符
$ 结尾 '^b.*3$'----以b开头,3结尾的任意字符
* 任意长度(次数),≥0
? 非贪婪模式,非贪婪模式尽可能少的匹配所搜索的字符串 '.*?(b.*?b).*'----从左至右第一个b和的二个b之间的内容(包含b)
+ 一次或多次
{2} 指定出现次数2次
{2,} 出现次数≥2次
{2,5} 出现次数2≤x≤5
| 或 “z|food”----能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”----则匹配“zood”或“food”或"zood"
[] 括号中任意一个符合即可(中括号里面没有分转义字符) '[abc]ooby123'----只要开头符合[]中任意一个即可
[^] 只要不出现[]的即可
[a-Z] 从小a到大Z
. 任意字符
\s 匹配不可见字符 \n \t '你\s好'----可以匹配‘你 好’
\S 匹配可见字符,即普通字符
\w 匹配下划线在内的任何单词字符
\W 和上一个相反
[\u4E00-\u9FA5] 只能匹配汉字
() 要取出的信息就用括号括起来
\d 数字
寻找2个字或者3个字的XX市或者XXX区
re.findall(re.compile('([\u4e00-\u9fa5]{2}市|[\u4e00-\u9fa5]{2}区|[\u4e00-\u9fa5]{3}市|[\u4e00-\u9fa5]{3}区)', re.S),
[\u4e00-\u9fa5]过滤中文
Xpath
article 选取所有article元素的所有子节点
/article 选取根元素article
article/a 选取所有属于article的子元素的a元素
//div 选取所有div子元素(不论出现在文档任何地方)
article//div 选取所有属于article元素的后代的div元素不管它出现在article之下的任何位置
//@class 选取所有名为class的属性
/article/div[1] 选取属于srticle子元素的第一个div所有子节点
/article/div[last()] 选取属于article子元素的最后一个div所有子节点
/article/div[last()-1] 选取属于article子元素的倒数第二个div所有子节点
//div[@lang] 选取所有拥有lang属性的div元素
//div[@lang='eng'] 选取所有lang属性为eng的div元素
/div/* 选取属于div元素的所有子节点
//* 选取所有元素
//div[@*] 选取所有带属性的div元素
//div/a | //div/p 选取所有div元素的a个p元素
//span | //ul 选取文档中的span和ul元素
article/div/p | //span 选取所有属于article元素的div元素和所有的span元素
1. 取得文章标题
>>> title = response.xpath('//div[@class="entry-header"]/h1/text()') >>> title [<Selector xpath='//div[@class="entry-header"]/h1/text()' data='2016 腾讯软件开发面试题(部分)'>] >>> title.extract() ['2016 腾讯软件开发面试题(部分)'] >>> title.extract()[0] '2016 腾讯软件开发面试题(部分)' >>> title.extract_first() '2016 腾讯软件开发面试题(部分)'
说明
1)extract()方法会把原数据的selector类型转变为列表类型
2)extract()会得到多个值,extract()[1]取第2个值
3)extract_first()得到第一个值,类型为字符串。extract_first(default='')如果没取到返回默认值
2. 取得发表日期
>>> response.xpath("//p[@class='entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·","").strip() '2017/02/18'
3. 点赞数,span标签里有很多class名,选一个看起来像唯一的,测试一下,然后用contains()函数简化操作
>>> response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract() ['2'] >>> response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract()[0] '2' >>> int(response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract()[0]) 2
Xpath函数
4. 收藏数,要用正则,re模块也是scrapy的内置模块,注意要用非贪婪匹配,否则只会取到8
>>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0] ' 28 收藏' >>> string = response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0] >>> import re >>> pattern = re.match(".*?(\d+).*", string) >>> pattern.group(1) '28'
可以简写为
>>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").re('.*?(\d+).*') ['28'] >>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").re('.*?(\d+).*')[0] '28'
节点轴选择
5. 使用列表推导式取得一个标签中的部分元素,如下取得职场和面试字样。适用于有些文章没评论标签的情况
![](https://i-blog.csdnimg.cn/blog_migrate/6dc8ac43e040eb8eb410bf35d2418037.png)
找到不是以"评论"结尾的元素 >>> response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract() ['职场', ' 9 评论 ', '面试'] >>> tag_list = response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract() >>> [element for element in tag_list if not element.strip().endswith("评论")] ['职场', '面试'] >>> tag_choose=[element for element in tag_list if not element.strip().endswith("评论")] >>> tags=",".join(tag_choose) >>> tags '职场,面试'
join()函数基本语法: 'sep'.join(seq)。表示以sep为分隔符,将seq中所有的元素合并成一个新的字符串
sep表示分隔符,可以为空;
seq表示要连接的数据,数据类型可以是列表,字符串,元组或者字典
- Element类型是'lxml.etree._Element',某种意义来说同时是一个列表
- 列表的需要使用tag\attrib\text三个不同的属性来获取我们需要的东西
- 变量.tag获取到的是标签名是---字符串
- 变量.attrib获取到的是节点标签a的属性---字典
- 变量.text获取到的是标签文本--字符串
xpath表格中取值
Ptable_items = response.xpath("//div[@class='Ptable']/div[@class='Ptable-item']/dl/dl")
others = {}
for item in Ptable_items:
dt = item.xpath("./dt/text()").extract_first().strip()
dd = item.xpath("./dd/text()").extract_first().strip()
if "机身内存" in dt:
if not one.get("capacity", ""):
one["capacity"] = dd
elif "颜色分类" in dt:
if not one.get("color", ""):
one["color"] = dd
Xpath string()提取多个子节点中的文本
<div>
<ul class="show"> <li>275万购昌平邻铁三居 总价20万买一居</li> <li>00万内购五环三居 140万安家东三环</li> <li>北京首现零首付楼盘 53万购东5环50平</li> <li>京楼盘直降5000 中信府 公园楼王现房</li> </ul> </div>
我想要把所有li标签中的文本提取出来,并且放到一个字符串中.
在网上查了下发现使用xpath的string()函数可以实现(string()和text()的区别请自行google)
先看下常见的方法:
>>> from lxml import etree
...
>>> result = html.xpath("//div/ul[@class='show']")[0] >>> result.xpath('string(.)') ' 275万购昌平邻铁三居 总价20万买一居 00万内购五 环三居 140万安家东三环 北京首现零首付楼盘 53万购东5环50平 京楼盘直降5000 中信府 公园楼王现房 '
这是我查到的多数人使用的方法,还有人使用了concat()函数,更麻烦就不提了.
但是上面的匹配明显感觉可以写到一条xpath里面的,为什么非要分开写!忍不住吐槽一下
xpath string()函数的调用写法:
>>> html.xpath("string(//div/ul[@class='show'])")
' 275万购昌平邻铁三居 总价20万买一居 00万内购五
环三居 140万安家东三环 北京首现零首付楼盘 53万购东5环50平
京楼盘直降5000 中信府 公园楼王现房 '
再吐槽下上面那种写法.在xpath语法里面,点(.)表示当前节点,当前节点不就是html.xpath("//div/ul[@class='show']")[0]
取到的节点元素吗!!!
Css
* 选取所有节点
#container 选取id为container的节点
.container 选取所有class包含container的节点
li a 选取所有li下的所有a节点
ul+p 选取ul后面的第一个p元素
div#container > ul 选取id为container的div的第一个ul子元素
ul ~ p 选取与ul相邻的所有p元素
a[title] 选取所有有title属性的a元素
a[href="http://jobbole.com"] 选取所有href属性为jobbole.com
a[href*="jobole"] 选取所有href属性包含jobbole的a元素
a[href^="http"] 选取所有href属性值以http开头的a元素
a[href$=".jpg"] 选取所有href属性值以.jpg结尾的a元素
input[type=radio]:checked 选取选中的radio的元素
div:not(#container) 选取所有id非container的div元素
li:nth-child(3) 选取第三个li元素
tr:nth-child(2n) 第偶数个tr元素
^ 开头
'^b.*'
-
-
-
-
以b开头的任意字符
$ 结尾
'^b.*3$'
-
-
-
-
以b开头,
3
结尾的任意字符
*
任意长度(次数),≥
0
? 非贪婪模式,非贪婪模式尽可能少的匹配所搜索的字符串
'.*?(b.*?b).*'
-
-
-
-
从左至右第一个b和的二个b之间的内容(包含b)
+
一次或多次
{
2
} 指定出现次数
2
次
{
2
,} 出现次数≥
2
次
{
2
,
5
} 出现次数
2
≤x≤
5
| 或 “z|food”
-
-
-
-
能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”
-
-
-
-
则匹配“zood”或“food”或
"zood"
[] 括号中任意一个符合即可(中括号里面没有分转义字符)
'[abc]ooby123'
-
-
-
-
只要开头符合[]中任意一个即可
[^] 只要不出现[]的即可
[a
-
Z] 从小a到大Z
. 任意字符
\s 匹配不可见字符 \n \t
'你\s好'
-
-
-
-
可以匹配‘你 好’
\S 匹配可见字符,即普通字符
\w 匹配下划线在内的任何单词字符
\W 和上一个相反
[\u4E00
-
\u9FA5] 只能匹配汉字
() 要取出的信息就用括号括起来
\d 数字