一、正则应用
猫眼电影项目(封装)
需求:爬取猫眼电影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)