Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
享興趣,傳播快樂,增長見聞,留下美好!
親愛的您,這里是LearningYard新學苑。
今天小編為大家帶來話說前端53-組件基礎,歡迎您的訪問。
Share interests, spread happiness, increase knowledge, and leave a good legacy!
Dear you, this is The LearningYard Academy.
Today Xiaobian brings you the knwowledge sharing of management principles (7): Crowd Relationship Theory (Mayo's Huasang experiment), welcome to your visit.
組件是 Vue.js 最強大的功能之一,組件可以擴展 HTML 元素,封裝可重用的代碼。組件系統讓我們可以用獨立可復用的小組件來構建大型應用,幾乎任意類型的應用的界面都可以抽象為一個組件樹:
Component is one of the most powerful functions of Vue.js Components can extend HTML elements and encapsulate reusable code. Component system allows us to build large-scale applications with independent and reusable small components, and the interface of almost any type of application can be abstracted into a component tree:
傳統方式編寫頁面:傳統方式下,我們進行前端開發時,都是一個html文檔對應一個或多個css樣式和js文件,且多個頁面中,可能出現相同的部分,例如網頁導航,例如網頁底部信息,又難免出現復用同樣的html結構,css樣式和js文件,但假如任意改動其中一部分,那整個項目中復用的部分都會隨之發生改變,就會造成依賴關系混亂,且不好維護。其次,傳統方式編寫項目,每一個頁面都是一個html文檔,每出現一個新頁面,就要新增一個html文檔和一個或多個css樣式及js文件,難免會存在文件較多的問題,每一個網頁大多都是一個獨立的部分,所以,代碼復用率不是很高。
Writing pages in the traditional way: In the traditional way, when we do front-end development, an html document corresponds to one or more css styles and js files, and in multiple pages, the same parts may appear, such as web navigation, such as information at the bottom of a web page, and it is inevitable that the same html structure, css styles and js files will be reused. However, if any part of them is changed at will, the reused parts in the whole project will change accordingly, which will lead to confusion of dependency and difficult maintenance. Secondly, in the traditional way of writing a project, every page is an html document. Every time a new page appears, an html document and one or more css styles and js files will be added, which will inevitably lead to the problem of more files. Most of each webpage is an independent part, so the code reuse rate is not very high.
組件方式編寫頁面:用組件方式來編寫頁面,其實簡單理解來說就是把一個完整的網頁拆分成一個又一個的組件,就比如說,一個網頁包含頭部導航,主體內容,底部信息。我們可以把網頁頭部導航劃分為一個組件,剩下的同樣對應劃分為組件。拿頂部導航這個組件來說,這個組件包含了實現頂部導航的html結構,css樣式和js代碼。每一個組件只負責對應的結構,樣式和交互,各司其職,互不干擾,然后由這些一個又有一個的組件組成了一個完整的頁面。且網頁被拆分為組件后,我們就可以進行 組件化編碼,最直觀的優點或亮點就是,組件復用,也就是多個網頁相同的部分,只需要寫一個組件然后按需引入就行。
Compiling pages in component mode: Compiling pages in component mode is, in fact, simply speaking, to split a complete web page into one component after another. For example, a web page contains header navigation, main content and bottom information. We can divide the page header navigation into a component, and the rest are also divided into components accordingly. Take the top navigation component as an example. This component includes html structure, css style and js code to realize top navigation. Each component is only responsible for the corresponding structure, style and interaction, each of which does its own job and does not interfere with each other, and then a complete page is composed of these components one after another. And after the web page is divided into components, we can carry out component coding. The most intuitive advantage or highlight is that component reuse, that is, the same part of multiple web pages, only needs to write a component and then introduce it as needed.
組件和模塊化:組件: 組件是可復用的 Vue 實例,且帶有一個名字。我們可以在一個通過 new Vue 創建的 Vue 根實例中,把這個組件作為自定義元素來使用。模塊: 分屬同一功能/業務的代碼進行隔離(分裝)成獨立的模塊,可以獨立運行,以頁面、功能或其他不同粒度劃分程度不同的模塊,位于業務框架層,模塊間通過接口調用,目的是降低模塊間的耦合,由之前的主應用與模塊耦合,變為主應用與接口耦合,接口與模塊耦合。
Component and modularity: Component: A component is a reusable instance of Vue with a name. We can use this component as a custom element in a root instance of Vue created through new Vue. Modules: Codes belonging to the same function/business are isolated (subpackaged) into independent modules, which can run independently. Modules with different degrees are divided by pages, functions or other granularity, which are located in the business framework layer. Modules are called through interfaces to reduce the coupling between modules, from the previous main application to the module, to the main application and the interface, and the interface and the module.
今天的分享就到這里了。如果您對今天的文章有什么獨特的想法,歡迎評論留言,讓我們相約明天,祝您今天過得開心快樂!
That's it for today's sharing. If you have any unique ideas for today's article, please leave a comment, let us meet tomorrow, I wish you a happy day!
翻譯:Google翻譯
本文由LearningYard新學苑原創,如有侵權,請聯系刪除。
文字&排版|李仕陽
審核|李煥
在爬取數據的過程中,需要對頁面解析和數據提取。
一般來講對我們而言,需要抓取的是某個網站或者某個應用的內容,提取有用的價值。內容一般分為兩部分,非結構化的數據和結構化的數據。
非結構化數據:先有數據,再有結構。
結構化數據:先有結構、再有數據。
不同類型的數據,我們需要采用不同的方式來處理。
13.1 正則表達式
13.1.1 為什么要學正則表達式
實際上爬蟲一共就四個主要步驟:
1. 明確目標 (要知道你準備在哪個范圍或者網站去搜索)
2. 爬 (將所有的網站的內容全部爬下來)
3. 取 (去掉對我們沒用處的數據)
4. 處理數據(按照我們想要的方式存儲和使用)
之前的案例里實際上省略了第3步,也就是"取"的步驟。因為我們down下了的數據是全部的網頁,這些數據很龐大并且很混亂,大部分的東西使我們不關心的,因此我們需要將之按我們的需要過濾和匹配出來。
那么對于文本的過濾或者規則的匹配,最強大的就是正則表達式,是Python爬蟲世界里必不可少的神兵利器。
13.1.2 什么是正則表達式
正則表達式,又稱規則表達式,通常被用來檢索、替換那些符合某個模式(規則)的文本。
正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。
給定一個正則表達式和另一個字符串,我們可以達到如下的目的:
1. 給定的字符串是否符合正則表達式的過濾邏輯(“匹配”);
2. 通過正則表達式,從文本字符串中獲取我們想要的特定部分(“過濾”)。
13.1.3正則表達式匹配規則
1. 字符匹配規則。
2. 預定義字符集(可以寫在字符集[…]中)。
3. 數詞量(用在字符或者(...)之后)
4.邊界匹配。
13.1.4 Python3下正則表達式的模塊的加載
在 Python 中,我們可以使用內置的 re 模塊來使用正則表達式。
import re
有一點需要特別注意的是,正則表達式使用 對特殊字符進行轉義,所以如果我們要使用原始字符串,只需加一個 r 前綴。
例子:
import re
#例子一
str1='nihao\tinghai'
print(str1)
#例子二
str2=r'nihao\tinghai'
print(str2)
運行結果:
nihao inghai
nihao\tinghai
13.1.5 compile 函數
compile 函數用于編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。
語法格式為:
re.compile(pattern[, flags])
參數:
pattern : 一個字符串形式的正則表達式
flags 可選,表示匹配模式,比如忽略大小寫,多行模式等,具體參數為:
re.I 忽略大小寫
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依賴于當前環境
re.M 多行模式
re.S 即為' . '并且包括換行符在內的任意字符(' . '不包括換行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依賴于 Unicode 字符屬性數據庫
re.X 為了增加可讀性,忽略空格和' # '后面的注釋
例子:
import re
pattern=re.compile(r'\d+') # 用于匹配至少一個數字
m=pattern.match('one12twothree34four') # 查找頭部,沒有匹配
print(m)
m=pattern.match('one12twothree34four', 2, 10) # 從'e'的位置開始匹配,沒有匹配
print(m)
m=pattern.match('one12twothree34four', 3, 10) # 從'1'的位置開始匹配,正好匹配
print(m)
運行結果:
None
None
<_sre.SRE_Match object; span=(3, 5), match='12'>
13.1.6 正則表達式對象
re.compile() 返回 RegexObject 對象。
re.MatchObject
group() 返回被 RE 匹配的字符串。
start() 返回匹配開始的位置。
end() 返回匹配結束的位置。
span() 返回一個元組包含匹配 (開始,結束) 的位置。
13.1.7 Python3 re模塊的2種使用方式
第一種方式:使用compile 函數
1.使用 compile() 函數將正則表達式的字符串形式編譯為一個 Pattern 對象
2.通過 Pattern 對象提供的一系列方法對文本進行匹配查找,獲得匹配結果,一個 Match 對象。
3.最后使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作
compile 函數用于編譯正則表達式,生成一個 Pattern 對象,它的一般使用形式如下:
import re
# 將正則表達式編譯成 Pattern 對象。
pattern=re.compile(r'\d+')
在上面,我們已將一個正則表達式編譯成 Pattern 對象,接下來,我們就可以利用 pattern 的一系列方法對文本進行匹配查找了。
Pattern 對象的一些常用方法主要有:
match 方法:從起始位置開始查找,一次匹配
search 方法:從任何位置開始查找,一次匹配
findall 方法:全部匹配,返回列表
finditer 方法:全部匹配,返回迭代器
split 方法:分割字符串,返回列表
sub 方法:替換
第二種方式:直接使用re. search()/re. findall ()方式。
例子:
import re
old_url='http://www.jikexueyuan.com/course/android/?pageNum=2'
total_page=20
html="""
<html lang="en">
<head>
<title>爬蟲測試</title>
</head>
<body>
<div class='topic'> <a href="http://jikexueyuan.com/welcone.html">歡迎參加《聽海的Python3接口自動化測試》
<div class='list'>
<ul>
<li><a href="http://jikexueyuan.com/1.html">這是第一條</a></li>
<li><a href="http://jikexueyuan.com/2.html">這是第二條</a></li>
<li><a href="http://jikexueyuan.com/3.html">這是第三條</a></li>
</ul>
</div>
</div>
</body>
</html>
"""
# f.close()
# #任務一:爬取網頁標題
#
# title=re.search('<title>(.*?)</title>',html,re.S).group(1)
# print(title)
#
# #任務二:爬取鏈接
# links=re.findall('href="(.*?)">',html)
# print(links)
# #任務三:爬取部分文字內容
# u_text=re.findall('<ul>(.*?)</ul>',html,re.S)[0]
# texts=re.findall('">(.*?)</a>',u_text,re.S)
# for every_text in texts:
# print(texts)
#任務四:sub實現翻頁
for i in range(2,total_page+1):
new_link=re.sub('pageNum=\d','pageNum=%d'%i,old_url,re.S)
print(new_link)
13.1.8 re模塊之match 方法
match 方法用于查找字符串的頭部(也可以指定起始位置),它是一次匹配,只要找到了一個匹配的結果就返回,而不是查找所有匹配的結果。它的一般使用形式如下:
match(string,begin,end)
其中,string 是待匹配的字符串,begin 和end 是可選參數,指定字符串的起始和終點位置,當你指定begin 和end 時,match 方法會根據指定的范圍去查詢,如果不指定begin 和end 時,match 方法默認匹配字符串的頭部。
當匹配成功時,返回一個 Match 對象,如果沒有匹配上,則返回 None。
綜合例子:
import re
#例子一
str1='ting123hai456'
pattern=re.compile(r'\d+') # 用于匹配至少一個數字
m1=pattern.match(str1) # 查找頭部,沒有匹配
print(m1)
#例子二
str2='ting123hai456'
pattern=re.compile(r'\d+') # 用于匹配至少一個數字
m2=pattern.match(str2,3,8) # 從'g'的位置開始匹配,沒有匹配
print(m2)
#例子三
str3='ting123hai456'
pattern=re.compile(r'\d+') # 用于匹配至少一個數字
m3=pattern.match(str3,4,8) # 從'1'的位置開始匹配,正好匹配
print(m3) # 返回一個 Match 對象
print(m3.group(0))
print(m3.start(0))
print(m3.end(0))
print(m3.span(0))
運行結果:
None
None
<_sre.SRE_Match object; span=(4, 7), match='123'>
123
4
7
(4, 7)
在上面,當匹配成功時返回一個 Match 對象,其中:
group([group1, …]) 方法:用于獲得一個或多個分組匹配的字符串,當要獲得整個匹配的子串時,可直接使用 group() 或 group(0);
start([group]) 方法:用于獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的索引),參數默認值為 0;
end([group]) 方法:用于獲取分組匹配的子串在整個字符串中的結束位置(子串最后一個字符的索引+1),參數默認值為 0;
span([group]) 方法:返回 (start(group), end(group))。
re.I 與re.S
1. re.I 表示忽略大小寫。
2. re.S 表示全文匹配。
例子一:re.I 表示忽略大小寫。
import re
pattern=re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小寫
m=pattern.match('Welcome To Reptiles')
print(m) # 匹配成功,返回一個 Match 對象
print(m.group(0)) # 返回匹配成功的整個子串
print(m.span(0)) # 返回匹配成功的整個子串的索引
print(m.group(1)) # 返回第一個分組匹配成功的子串
print(m.span(1)) # 返回第一個分組匹配成功的子串的索引
print(m.group(2)) # 返回第二個分組匹配成功的子串
print(m.span(2)) # 返回第二個分組匹配成功的子串
print(m.groups()) # 等價于 (m.group(1), m.group(2), ...)
print(m.group(3)) # compile(r'([a-z]+) ([a-z]+)')只是匹配了2組規則,不存在第三個分組
運行結果:
<_sre.SRE_Match object; span=(0, 10), match='Welcome To'>
Welcome To
(0, 10)
Welcome
(0, 7)
To
(8, 10)
('Welcome', 'To')
IndexError: no such group
re.S表示全文匹配,講findall()方法的時候,再用具體的例子展示。
13.1.9 re模塊之search 方法
search 方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一個匹配的結果就返回,而不是查找所有匹配的結果,它的一般使用形式如下:
search(string,begin,end)
其中,string 是待匹配的字符串,begin 和end 是可選參數,指定字符串的起始和終點位置,當你指定begin 和end 時,search 方法會根據指定的范圍去查詢,如果不指定begin 和end 時,match 方法默認任何位置,只要找到了一個匹配的結果就返回。
當匹配成功時,返回一個 Match 對象,如果沒有匹配上,則返回 None。
綜合例子1:
import re
#例子一
str1='ting123hai456'
pattern=re.compile('\d+')
m1=pattern.search(str1) # 查找字符串任意位置,這里如果使用 match 方法則不匹配
print(m1)
print(m1.group())
print(m1.span())
#例子二
str2='ting123hai456'
pattern=re.compile('\d+')
m2=pattern.search(str2,4,8) # 指定字符串區間
print(m2)
print(m2.group())
print(m2.span())
運行結果:
<_sre.SRE_Match object; span=(4, 7), match='123'>
123
(4, 7)
<_sre.SRE_Match object; span=(4, 7), match='123'>
123
(4, 7)
綜合例子2:
import re
#例子一
str1='ting123hai456'
pattern=re.compile('\d+')
m1=pattern.search(str1) # 查找字符串任意位置,這里如果使用 match 方法則不匹配
print(m1)
print(m1.group())
print(m1.span())
#例子二
str2='ting123hai456'
pattern=re.compile('\d+')
m2=pattern.search(str2,7,13) # 指定字符串區間
print(m2)
print(m2.group())
print(m2.span())
運行結果:
<_sre.SRE_Match object; span=(4, 7), match='123'>
123
(4, 7)
<_sre.SRE_Match object; span=(10, 13), match='456'>
456
(10, 13)
13.1.10 re模塊之findall 方法
上面的 match 和 search 方法都是一次匹配,只要找到了一個匹配的結果就返回。然而,在大多數時候,我們需要搜索整個字符串,獲得所有匹配的結果。
findall 方法的使用形式如下:
findall(string,begin,end)
其中,string 是待匹配的字符串,begin 和end 是可選參數,指定字符串的起始和終點位置,當你指定begin 和end 時,findall 方法會根據指定的范圍去查詢,以列表形式返回全部能匹配的子串,如果不指定begin 和end 時,match 方法會全文搜索,以列表形式返回全部能匹配的子串。
findall 以列表形式返回全部能匹配的子串,如果沒有匹配,則返回一個空列表。
綜合例子:
import re
#例子一
str1='hello123hell world456hel'
pattern=re.compile('hel') # 查找數字
m1=pattern.findall(str1)
print(m1)
#例子二
str2='hello123hell world456hel'
pattern=re.compile('hel') # 查找 hel
m2=pattern.findall(str2, 7, 14)
print(m2)
#例子三
str3='hello123hell world456hel'
pattern=re.compile('hel') # 查找 hel
m3=pattern.findall(str3, 7, 25)
print(m3)
運行結果:
['hel', 'hel', 'hel']
['hel']
['hel', 'hel']
13.1.11 re模塊之finditer 方法
finditer 方法的行為跟 findall 的行為類似,也是搜索整個字符串,獲得所有匹配的結果。但它返回一個順序訪問每一個匹配結果(Match 對象)的迭代器。
例子:
import re
pattern=re.compile(r'\d+')
m1=pattern.finditer('hello 123456 789')
m2=pattern.finditer('one1two2three3four4', 0, 10)
print(type(m1))
print(type(m2))
print('----- m1 ------')
for a1 in m1: # a1 是 Match 對象
print('matching string: {}, position: {}'.format(a1.group(), a1.span()))
print('----- m2 ------')
for a2 in m2:
print('matching string: {}, position: {}'.format(a2.group(), a2.span()))
運行結果:
<class 'callable_iterator'>
<class 'callable_iterator'>
----- m1 ------
matching string: 123456, position: (6, 12)
matching string: 789, position: (13, 16)
----- m2 ------
matching string: 1, position: (3, 4)
matching string: 2, position: (7, 8)
13.1.12 split 方法
split 方法按照能夠匹配的子串將字符串分割后返回列表,它的使用形式如下:
split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次數,不指定將全部分割。
例子:
import re
p=re.compile(r'[\s\,\;]+')
print(p.split('a,b;; c d'))
運行結果:
['a', 'b', 'c', 'd']
13.1.13 sub 方法
sub 方法用于替換。它的使用形式如下:
sub(repl, string[, count])
其中,repl 可以是字符串也可以是一個函數:
如果 repl 是字符串,則會使用 repl 去替換字符串每一個匹配的子串,并返回替換后的字符串,另外,repl 還可以使用 id 的形式來引用分組,但不能使用編號 0;
如果 repl 是函數,這個方法應當只接受一個參數(Match 對象),并返回一個字符串用于替換(返回的字符串中不能再引用分組)。
count 用于指定最多替換次數,不指定時全部替換。
例子一:
import re
p=re.compile('123(.*?)123')
s='123asdfxxIxxxxLovexxded123'
f=p.sub('123456789',s)
print(f)
運行結果:
123456789
例子二:
import re
p=re.compile(r'(\w+) (\w+)') # \w=[A-Za-z0-9]
s='hello 123, hello 456'
print(p.sub(r'hello world', s)) # 使用 'hello world' 替換 'hello 123' 和 'hello 456'
print(p.sub(r' ', s)) # 引用分組
def func(m):
return 'hi' + ' ' + m.group(2)
print(p.sub(func, s))
print(p.sub(func, s, 1)) # 最多替換一次
運行結果:
hello world, hello world
123 hello, 456 hello
hi 123, hi 456
hi 123, hello 456
13.1.14 貪婪模式與非貪婪模式
在使用正則匹配的時候,有2種模式:
【貪婪模式】:在整個表達式匹配成功的前提下,盡可能多的匹配 ( * );
【非貪婪模式】:在整個表達式匹配成功的前提下,盡可能少的匹配 ( ? );
Python里數量詞默認是貪婪的。
綜合例子一:
import re
#例子一 貪婪模式
s='abbbc'
p=re.compile('ab*')
f1=p.findall(s)
print(f1)
#例子二 非貪婪模式
s='abbbc'
p=re.compile('ab*?')
f2=p.findall(s)
print(f2)
運行結果:
['abbb']
['a']
運行結果說明:
使用貪婪的數量詞的正則表達式 ab* ,匹配結果: abbb。
* 決定了盡可能多匹配 b,所以a后面所有的 b 都出現了。
使用非貪婪的數量詞的正則表達式ab*?,匹配結果: a。
即使前面有 *,但是 ? 決定了盡可能少匹配 b,所以沒有 b。
綜合例子二:
import re
html="aa<div>test1</div>bb<div>test2</div>cc"
#例子一 貪婪模式
p=re.compile('<div>.*</div>')
f1=p.findall(html)
print(f1)
#例子二 非貪婪模式
p=re.compile('<div>.*?</div>')
f2=p.findall(html)
print(f2)
運行結果:
['<div>test1</div>bb<div>test2</div>']
['<div>test1</div>', '<div>test2</div>']
運行結果說明:
使用貪婪的數量詞的正則表達式:<div>.*</div>
匹配結果:<div>test1</div>bb<div>test2</div>
這里采用的是貪婪模式。在匹配到第一個“</div>”時已經可以使整個表達式匹配成功,但是由于采用的是貪婪模式,所以仍然要向右嘗試匹配,查看是否還有更長的可以成功匹配的子串。匹配到第二個“</div>”后,向右再沒有可以成功匹配的子串,匹配結束,匹配結果為“<div>test1</div>bb<div>test2</div>”
使用非貪婪的數量詞的正則表達式:<div>.*?</div>
匹配結果:<div>test1</div>
正則表達式二采用的是非貪婪模式,在匹配到第一個“</div>”時使整個表達式匹配成功,由于采用的是非貪婪模式,所以結束匹配,不再向右嘗試,匹配結果“<div>test1</div>”。
13.1.15 使用正則表達式的爬蟲的案例
學會了正則表達式提取數據的相關方法之后,我們就可以進行對爬取到的全部網頁源代碼進行篩選了,下面講案例。
案例一:爬取極客學院課程
代碼:
import re,requests
class spider(object):
def __init__(self):
print("開始爬取內容")
def getsource(self,source):
html=requests.get(source)
return html.text
def changepage(self,url,total_page):
now_page=int(re.search('pageNum=(\d+)',url,re.S).group(1))
page_group=[]
for i in range(now_page,total_page+1):
link=re.sub('pageNum=(\d+)','pageNum=%s'%i,url,re.S)
page_group.append(link)
return page_group
def geteveryclass(self,html):
everyclass=re.findall('<li id="(.*?)</li>',html,re.S)
return everyclass
def getinfo(self,eachclass):
info={ } #定義一個空的字典
info['title']=re.search('title="(.*?)" alt="',eachclass,re.S).group(1)
info['content']=re.findall('display: none;">[\s]*([\s\S]*?)[\s]*</p>', eachclass)[0]
classlevel=re.findall('<em>(.*?)</em>',eachclass, re.S)
info['classtime']=classlevel[0]
info['classlevel']=classlevel[1]
info['learnnum']=re.search('"learn-number">(.*?)</em>', eachclass, re.S).group(1)
return info
def saveinfo(self,classinfo):
f=open(u'info.txt','a')
for each in classinfo:
f.writelines('title:'+each['title']+'\n')
f.writelines('content:' + each['content'] + '\n')
f.writelines('classtime:' + each['classtime'] + '\n')
f.writelines('classlevel:' + each['classlevel'] + '\n')
f.writelines('learnnum:' + each['learnnum'] + '\n')
f.close()
if __name__=='__main__':
classinfo=[] #定義一個空的列表
url='http://www.jikexueyuan.com/course/?pageNum=1' # 初始的url
jikespider=spider() #實例化一個類 jikespider
all_links=jikespider.changepage(url,20) #調用jikespider里的changepage(url,20)方法,獲取1~20頁的url
for link in all_links:
print("正在處理頁面:"+ link)
html=jikespider.getsource(link) # 調用jikespider里的getsource()方法,獲取每個html的text
everyclass=jikespider.geteveryclass(html) #調用jikespider里的geteveryclass()方法爬取everyclassh的html的text存到everyclass列表里
#print(everyclass)
for each in everyclass:
#print(each)
info=jikespider.getinfo(each) #調用jikespider里的getinfo()方法,獲取每個視頻的title、content、classtime、classlevel、learnnum
classinfo.append(info)
print(classinfo)
jikespider.saveinfo(classinfo)
13.2 XPath介紹
正則雖然很強大,但是正則語法相對比較復雜,比較難掌握,還有另外一種方法:XPath,我們可以先將 HTML文件 轉換成XML文檔,然后用 XPath 查找 HTML 節點或元素。
13.2.1 什么是XML
XML 指可擴展標記語言(EXtensible Markup Language)
XML 是一種標記語言,很類似 HTML
XML 的設計宗旨是傳輸數據,而非顯示數據
XML 的標簽需要我們自行定義。
XML 被設計為具有自我描述性。
XML 是 W3C 的推薦標準
13.2.2 XML 和 HTML 的區別
XML文檔示例:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
HTML DOM 模型示例:
HTML DOM 定義了訪問和操作 HTML 文檔的標準方法,以樹結構方式表達 HTML 文檔。
13.2.3 XML的節點關系
1. 父節點(Parent)
每個元素以及屬性都有一個父。
下面是一個簡單的XML例子中,book 元素是 title、author、year 以及 price 元素的父:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
2. 子節點(Children)
元素節點可有零個、一個或多個子。
在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
3. 同胞(Sibling)
擁有相同的父的節點。
在下面的例子中,title、author、year 以及 price 元素都是同胞:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
4. 先輩(Ancestor)
某節點的父、父的父,等等。
在下面的例子中,title 元素的先輩是 book 元素和 bookstore 元素:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
5. 后代(Descendant)
某個節點的子,子的子,等等。
在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
13.2.4 什么是XPath
XPath (XML Path Language) 是一門在 XML 文檔中查找信息的語言,可用來在 XML 文檔中對元素和屬性進行遍歷。
W3School官方文檔:http://www.w3school.com.cn/xpath/index.asp
13.2.5 XPath 開發工具
1.開源的XPath表達式編輯工具:XMLQuire(XML格式文件可用)
2.Chrome插件 XPath Helper
3.Firefox插件 XPath Checker
13.2.6 選取節點
XPath 使用路徑表達式在 XML 文檔中選取節點。節點是通過沿著路徑或者 step 來選取的。
下面列出了最有用的路徑表達式:
謂語(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。
【選取未知節點】
XPath 通配符可用來選取未知的 XML 元素。
實例
在下面的表格中,我們列出了一些路徑表達式,以及這些表達式的結果:
【選取若干路徑】
通過在路徑表達式中使用“|”運算符,您可以選取若干個路徑。
實例
在下面的表格中,我們列出了一些路徑表達式,以及這些表達式的結果:
13.2.7 XPath 運算符
下面列出了可用在 XPath 表達式中的運算符:
JavaScript作為Web前端開發的基石,其強大的功能和靈活性不僅體現在網頁的動態交互上,更在于其處理數據的能力。數組遍歷是JavaScript中最常見的操作之一,尤其在算法題的求解過程中,它扮演著至關重要的角色。本文將深入探討JavaScript中數組遍歷的多種方法,通過具體的算法題示例,幫助讀者掌握高效解決問題的技巧。
在JavaScript中,數組遍歷可以通過多種方式進行,每種方法都有其特點和適用場景:
const numbers=[1, 2, 3, 4, 5];
// 使用for循環遍歷
for (let i=0; i < numbers.length; i++) {
console.log(numbers[i]);
}
// 使用forEach遍歷
numbers.forEach(number=> console.log(number));
// 使用map創建新數組
const doubled=numbers.map(number=> number * 2);
console.log(doubled); // 輸出: [2, 4, 6, 8, 10]
數組遍歷方法本質上是通過迭代數組中的每一個元素來執行特定的邏輯操作。不同的方法提供不同的操作能力,如map用于變換,filter用于篩選,而reduce用于聚合。
假設我們有一道算法題,要求找出數組中所有偶數,并返回它們的平方和。
function sumOfSquaresEvenNumbers(numbers) {
return numbers
.filter(number=> number % 2===0) // 篩選偶數
.map(number=> number * number) // 平方
.reduce((acc, curr)=> acc + curr, 0); // 求和
}
const result=sumOfSquaresEvenNumbers([1, 2, 3, 4, 5, 6]);
console.log(result); // 輸出: 56
function optimizedSumOfSquaresEvenNumbers(numbers) {
let sum=0;
for (let number of numbers) {
if (number % 2===0) {
sum +=number * number;
}
}
return sum;
}
const optimizedResult=optimizedSumOfSquaresEvenNumbers([1, 2, 3, 4, 5, 6]);
console.log(optimizedResult); // 輸出: 56
數組遍歷不僅是JavaScript編程的基礎,也是解決復雜算法問題的利器。通過本文的探討,我們不僅學習了多種數組遍歷的方法,還掌握了如何在實際問題中選擇合適的遍歷策略,以提高代碼的效率和可讀性。未來,隨著JavaScript語言的不斷發展,新的數組方法和迭代器模式將進一步豐富我們的編程工具箱,為開發者提供更加高效和靈活的解決方案。掌握數組遍歷的技巧,意味著在算法題的求解中擁有了更多的選擇和自信,這也是前端開發者邁向更高層次的關鍵一步。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。