一、正則應用
貓眼電影項目(封裝)
需求:爬取貓眼電影top100,並篩選出電影名、主演、上映時間、評分信息。
1.取dl
2.取dd
3.取電影名
4.取主演
5.取上映時間
6.取評分
import requests,re,json
class Maoyan():
def __init__(self,url):
self.url = url
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
self.movie_list = []
self.parse()
def parse(self):
# 爬取10頁
for i in range(10):
url = self.url+'?offset=%s'%(i*10)
response = requests.get(url,headers=self.headers)
# print(response.text)
# 提取信息
# 電影名、主演、上映時間、評分
dl_pattern = re.compile(r'<dl class="board-wrapper">(.*?)</dl>',re.S)
dl = dl_pattern.search(response.text).group()
dd_pattern = re.compile(r'<dd>(.*?)</dd>',re.S)
dd = dd_pattern.findall(dl)
movie_name_pattern = re.compile(r'title="(.*?)"')
role_pattern = re.compile(r'<p class="star">(.*?)</p>',re.S)
date_pattern = re.compile(r'<p class="releasetime">(.*?)</p>')
score_pattern = re.compile(r'<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>')
for one in dd:
item = {}
movie_name = movie_name_pattern.search(one).group()
role = role_pattern.search(one).group(1).strip()[3:]
date = date_pattern.search(one).group(1)[5:]
score = score_pattern.search(one).group(1)+score_pattern.search(one).group(2)
item = {'movie_name':movie_name,'role':role,'date':date,'score':score}
self.movie_list.append(item)
# print(self.movie_list)
# 將電影信息寫入到json文件中
with open('movie.json','w',encoding='utf-8') as fp:
json.dump(self.movie_list,fp)
if __name__ == '__main__':
base_url = 'https://maoyan.com/board/4'
Maoyan(base_url)
# 從json文件中讀取信息
with open('movie.json','r') as fp:
movie_list = json.load(fp)
# 就可以任意操作了
for movie in movie_list:
print(movie)
json文件儲存的是unicode編碼,這樣更方便傳輸,避免因爲編碼不同而出現的錯誤。
股吧項目
需求:取12頁的閱讀數,評論數,標題,作者,更新時間,詳情頁url信息
1.取ul
2.取li
3.取閱讀數,評論數
4.取標題
5.取作者
6.取更新時間
7.取詳情頁url
import requests,re,json
base_url = 'http://guba.eastmoney.com/default,99_%s.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
infos = []
for i in range(1,13):
response = requests.get(base_url%i,headers=headers)
ul_pattern = re.compile(r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)
ul = ul_pattern.search(response.text).group(1)
li_pattern = re.compile(r'<li>(.*?)</li>',re.S)
li = li_pattern.findall(ul)
click_comment_pattern = re.compile(r'<cite>(.*?)</cite>(.*?)<cite>(.*?)</cite>',re.S)
title_pattern = re.compile(r'title="(.*?)" class="note">')
author_pattern = re.compile(r'<font>(.*?)</font></a>')
time_pattern = re.compile(r'<cite class="last">(.*?)</cite>')
url_pattern = re.compile(r'</em> <a href="(.*?)" title="')
for one in li:
click = click_comment_pattern.search(one).group(1).strip()
comment = click_comment_pattern.search(one).group(3).strip()
if title_pattern.search(one):
title = title_pattern.search(one).group(1)
else:
title = ''
author = author_pattern.search(one).group(1)
time = time_pattern.search(one).group(1)
if url_pattern.search(one):
url = 'http://guba.eastmoney.com'+url_pattern.search(one).group(1)
else:
url = ''
item = {'click':click,'comment':comment,'title':title,'author':author,'time':time,'url':url}
infos.append(item)
print(infos)
封裝
import requests,re,json
class Guba():
def __init__(self,base_url):
self.base_url = base_url
self.infos = []
self.get_info()
def get_content(self,url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code==200:
return response.text
def get_info(self):
for i in range(1, 13):
html = self.get_content(self.base_url%i)
ul_pattern = re.compile(
r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)
ul = ul_pattern.search(html).group(1)
li_pattern = re.compile(r'<li>(.*?)</li>', re.S)
li = li_pattern.findall(ul)
click_comment_pattern = re.compile(
r'<cite>(.*?)</cite>(.*?)<cite>(.*?)</cite>', re.S)
title_pattern = re.compile(r'title="(.*?)" class="note">', re.S)
author_pattern = re.compile(r'<font>(.*?)</font></a>', re.S)
time_pattern = re.compile(r'<cite class="last">(.*?)</cite>', re.S)
url_pattern = re.compile(r'</em> <a href="(.*?)" title="', re.S)
for one in li:
click = click_comment_pattern.search(one).group(1).strip()
comment = click_comment_pattern.search(one).group(3).strip()
if title_pattern.search(one):
title = title_pattern.search(one).group(1)
else:
title = ''
author = author_pattern.search(one).group(1)
time = time_pattern.search(one).group(1)
if url_pattern.search(one):
url = 'http://guba.eastmoney.com' + url_pattern.search(one).group(1)
else:
url = ''
item = {'click': click, 'comment': comment, 'title': title,
'author': author, 'time': time, 'url': url}
self.infos.append(item)
with open('guba_oop.json','w',encoding='utf-8') as fp:
json.dump(self.infos,fp)
if __name__ == '__main__':
Guba('http://guba.eastmoney.com/default,99_%s.html')
with open('guba.json', 'r') as fp:
info = json.load(fp)
for one in info:
print(one)
二、xml
(一)什麼是xml
- xml稱爲可擴展標記語言
- xml具有自描述特性,是一種半結構化數據
- xml的設計宗旨是用來傳輸數據,也可以作爲配置文件記錄一些重要的配置信息
(二)xml和html的區別
1.語法要求不同
-
在html中不區分大小寫;xml中嚴格區分
-
在html中,如果上下文清楚地顯示出段落或者列表在何處結尾,那麼可以省略
</p>
或者</li>
標記;在xml中,是嚴格的樹狀結構,絕不能省略任何標記 -
在xml,擁有單個標記而沒有匹配的結束標記的元素,必須用一個/字符作爲結尾。
<a href='XXXXXXXX'/>
-
在xml中,屬性值必須封裝在引號中;在html中,引號可用可不用。
-
在html中,屬性名可以沒有屬性值;xml必須有。
-
在xml中,空白部分不會被解析器自動刪除;html是會過濾掉空格的。
2.作用不同
xml主要是用來傳輸數據的。
html主要是用來顯示數據,以及更好的顯示數據的。
3.標記不同
xml沒有固定的標記。
html的標籤是固定的。
三、xpath
(一)什麼是xpath
xpath是一種語法,用來提取xml或者html頁面內容的語法。
(二)xpath語法內容
-
元素:指一個xml的標籤以及標籤的所有內容
-
屬性:class、name
-
內容:a標籤的內容就是‘\n aaa\n 1’和‘\n 2’,b標籤的內容就是bbb
<a> aaa 1<b>bbb</b> 2</a>
-
標籤:和元素一樣
1.選取節點
- nodename:選取此標籤的所有子標籤
- /:從根節點開始選取
- //:從任意位置開始選取
- .:選取當前節點
- …:選取父節點
- @:選取屬性
- text():選取內容
2.謂語
英語中的謂語用來限定。
xpath中的謂語也是用來限定選取的內容的。
- /bookstore/book[1]:表示取bookstore下面的第一個book標籤
- /bookstore/book[last()]:表示取bookstore下面的最後一個book標籤
- /bookstore/book[last()-1]:表示取bookstore下面的倒數第二個book標籤
- /bookstore/book[position()>1]:表示從bookstore下面的第二本書開始取
- //title[@lang]:取有lang屬性的title標籤
- //title[@lang=“eng”]:取有lang屬性,且lang屬性值爲eng的title標籤
3.選取未知節點
- *:匹配任意節點
- @*:匹配任意屬性
4.選取若干路徑
- //title|//price:選取所有的title標籤和price標籤
四、在python中如何使用xpath
通過lxml模塊,可以使用xpath語法篩選元素。
方法
導包
from lxml import etree
方法一
將字符串形式的xml內容,解析成element對象的方法:
html_element = etree.HTML(html_str)
from lxml import etree
text = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a><li>
<li class="item-1"><a href="link2.html">second item</a><li>
<li class="item-inactive"><a href="link3.html">third item</a><li>
<li class="item-1"><a href="link4.html">fourth item</a><li>
<li class="item-0"><a href="link5.html">fifth item</a><li>
</ul>
</div>
"""
html = etree.HTML(text)
# print(html) # <Element html at 0x3b62e48>
html_str = etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8')
print(html_str)
注:tostring方法的返回值是bytes類型,轉換爲string類型需要解碼。
方法二
將一個html文件轉化成element對象的方法:
html = etree.parse('demo.html')
etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8')
當使用parse方法解析一個xml或者html文件時,語法必須嚴格按照xml的標籤語法,且標籤必須對應。
demo.html
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html"><span class="bold">third item</span>></a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
py文件
from lxml import etree
html = etree.parse('demo.html')
# print(html) # <lxml.etree._ElementTree object at 0x0000000003B51F48>
print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))
element對象可以調用xpath方法
html_element.xpath(),返回值都是一個存放element對象的列表,還可以繼續調用xpath方法,繼續篩選元素。
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive">
<a href="link3.html" class="a_class_1">aaaa</a>
<span class="span_item1">span_text1</span>
</li>
<li class="item-1">
test
<a href="link4.html" class="a_class_0">fourth item
<span class="span_item2">span_text2</span></a>
</li>
<li class="item-0">
<a href="link5.html" class="bold">fifth item</a>
</li>
</ul>
</div>
'''
html = etree.HTML(text)
# print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))
'''
<html>
<body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive">
<a href="link3.html" class="a_class_1">aaaa</a>
<span class="span_item1">span_text1</span>
</li>
<li class="item-1">
test
<a href="link4.html" class="a_class_0">fourth item
<span class="span_item2">span_text2</span></a>
</li>
<li class="item-0">
<a href="link5.html" class="bold">fifth item</a>
</li>
</ul>
</div>
</body>
</html>
'''
# 獲取所有的 <li> 標籤
li_list = html.xpath('//li')
# print(li_list)
# 繼續獲取<li> 標籤的所有 class屬性
li_class_list = html.xpath('//li/@class')
# print(li_class)
# 繼續獲取<li>標籤下href 爲 link1.html 的 <a> 標籤
li_a_href = html.xpath('//li/a[@href="link1.html"]')
# print(li_a_href)
# 獲取<li> 標籤下的所有 <span> 標籤(包括孫子span)
li_span = html.xpath('//li//span')
# print(li_span)
# 獲取 <li> 標籤下的<a>標籤裏的所有 class
li_a_class = html.xpath('//li/a/@class')
# print(li_a_class)
# 獲取最後一個 <li> 的 <a> 的 href
lastli_a_href = html.xpath('//ul/li[last()]/a/@href')
# print(lastli_a_href)
# 獲取倒數第二個元素的內容
con = html.xpath('//*[last()-1]/text()')
# print(con)
# 獲取 class 值爲 bold 的標籤名
bold = html.xpath('//*[@class="bold"]')
print(bold[0].tag)
from lxml import etree
html = '''
<bookstore>
<title>新華書店</title>
<book href="http://www.langlang2017.com/">
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="zh">Learning XML</title>
<price>39.95</price>
</book>
<book href="www.baidu.com">
<title>python 大全</title>
<price>99.95</price>
</book>
</bookstore>
'''
tree = etree.HTML(html)
# print(etree.tostring(tree,pretty_print=True,encoding='utf-8').decode('utf-8'))
# (1)獲取文檔中的所有book節點的第一個book節點
first_book = tree.xpath('//book[1]')
# print(first_book)
# (2)獲取第一個book節點
first_book = first_book[0]
# (3)獲取first_book當前節點下的href
href = first_book.xpath('.//@href')
# print(href)
# (4)獲取當前節點的父節點下的book節點的href屬性
href2 = first_book.xpath('../book/@href')
# print(href2)
# (5)獲取價格小於40的書的書名
bookname = tree.xpath('//book[price<40]/title/text()')
# print(bookname)
# (6)獲取價格等於99.95的書的書名
bookname2 = tree.xpath('//book[price=99.95]/title/text()')
# print(bookname2)
# (7)獲取book標籤下面的title和price標籤
title_price = tree.xpath('//book/title|//book/price')
# print(title_price)
# (8)獲取屬性href含有baidu字符串的book標籤,獲取此標籤的書名
title = tree.xpath('//book[contains(@href,"baidu")]/title/text()')
# print(title)
# (9)獲取前面兩個屬於bookstore標籤的子標籤的book標籤,獲取此標籤的書名
title2 = tree.xpath('//bookstore/book[position()<3]/title/text()')
# print(title2)
# (10)匹配任意有屬性的節點
result = tree.xpath('//*[@*]')
# print(result)
# (11)獲取所有帶有屬性title標籤,獲取此標籤的內容
result2 = tree.xpath('//title[@*]/text()')
print(result2)