正則表達式(特殊字符)
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. 使用列表推導式取得一個標簽中的部分元素,如下取得職場和面試字樣。適用於有些文章沒評論標簽的情況


找到不是以"評論"結尾的元素 >>> 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 數字