文章目录
一、正则表达式
1.为什么要学正则表达式
爬虫一共四个主要步骤:
- 明确目标 (要知道你准备在哪个范围或者网站去搜索)
- 爬 (将所有的网站的内容全部爬下来)
- 取 (去掉对我们没用处的数据)
- 处理数据(按照我们想要的方式存储和使用)
2.什么是正则表达式
正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。
小例子:
3.re 模块一般使用步骤
- 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
注意: re对特殊字符进行转义,如果使用原始字符串,只需加一个 r 前缀- 通过 Pattern 对象对文本进行匹配查找,获得匹配结果,一个 Match 对象。
- 使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作
正则表达式实现步骤
import re
text = """
2020-10-10
2020-11-11
2030/12/12
"""
# 1. 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
# 注意: re对特殊字符进行转义,如果使用原始字符串,只需加一个 r 前缀
pattern = re.compile(r'\d{4}-\d{1,2}-\d{1,2}') # 2020-4-11, 无分组的规则
pattern = re.compile(r'(\d{4})-(\d{1,2})-(\d{1,2})') # 2020-4-11, 有分组的规则
pattern = re.compile(r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})') # 2020-4-11, 有命名分组的规则
# 2. 通过 Pattern 对象对文本进行匹配查找,获得匹配结果,一个 Match 对象。
# search从给定的字符串中寻找一个符合规则的字符串, 只返回一个
result = re.search(pattern, text)
print(result)
# 3. 使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作
print("匹配到的信息:", result.group()) # 返回的是匹配到的文本信息
print("匹配到的信息:", result.groups()) # 返回的是位置分组, ('2020', '10', '10')
print("匹配到的信息:", result.groupdict()) # 返回的是关键字分组.{'year': '2020', 'month': '10', 'day': '10'}
#运行结果:
<re.Match object; span=(1, 11), match='2020-10-10'>
匹配到的信息: 2020-10-10
匹配到的信息: ('2020', '10', '10')
匹配到的信息: {'year': '2020', 'month': '10', 'day': '10'}
Pattern和Match对象方法汇总
1.pattern对象方法
正则表达式编译成 Pattern 对象, 可以利用 pattern 的一系列方法对文本进行匹配查找
Pattern 对象的一些常用方法主要有:
2.match对象方法
match 方法用于查找字符串的头部(也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果就返回, 而不是查找所有匹配的结果。它的一般使用形式如下:match(string[, pos[, endpos]])
string :待匹配的字符串
pos :字符串的起始位置, 默认值是 0
endpos :字符串的终点位置, 默认值是 len (字符串长度)
3.search
search 方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有 匹配的结果,它的一般使用形式如下:search(string[, pos[, endpos]])
当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。
4.findall和finditer方法
findall 方法搜索整个字符串,获得所有匹配的结果。使用形式如下:findall(string[, pos[, endpos]])
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每 一个匹配结果(Match 对象)的迭代器。
5.split方法
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
maxsplit 指定最大分割次数,不指定将全部分割split(string[, maxsplit])
import re
p = re.compile(r'[\s\,\;]+')
print p.split('a,b;; c d')
6.sub方法
sub 方法用于替换。它的使用形式如下:
sub(repl, string[, count])
repl 可以是字符串也可以是一个函数:
- 1). 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还 可以使用 id 的形式来引用分组,但不能使用编号 0;
- 2). 如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符 串中不能再引用分组)。
count 用于指定最多替换次数,不指定时全部替换。
import re
p = re.compile(r'(\w+) (\w+)')
s = 'hello 123, hello 456'
print(p.sub(r'hello word', s)) # 使用'hello word' 替换'hello 123, hello 456'
print(p.sub(r'\2 \1', s)) # \数字:引用分组
def func(m):
return 'hi' + ' ' + m.group(2)
print(p.sub(func, s))
print(p.sub(func, s, 1)) # 最多替换1次
运行结果:
7.匹配中文
在某些情况下,我们想匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围主要在 [u4e00- u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。
8.正则常量
re.ASCII
re.IGNORECASE 忽略大小写
re.M 多行
re.S .代表任意字符
import re
# 1. re.ASCII
text = '正则表达式re模块'
# 匹配所有字母数字下划线, 默认匹配中文,不匹配中文时,指定flags=re.A
result = re.findall(pattern=r'\w+', string = text, flags=re.A) # 只匹配ascii
print(result)
# 2. 忽略大小写 re.IGNORECASE
text= 'hello word HEllo python'
result = re.findall(r'he\w+o' , text, re.I)
print(result) # ['hello', 'HEllo']
# 3. re.M 多行
text = 'hello 123 \n 234 453word '
result = re.findall(r'^he.*?', text, re.M)
print(result)
# 4. re.S .代表任意字符
text = 'hello \n word'
result = re.findall(r'^he.*?ld$', text, re.S)
print(result)
运行结果:
9.贪婪模式与非贪婪模式
- 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );
使用贪婪的数量词的正则表达式 ab* ,匹配结果: abbb。
*决定了尽可能多匹配 b,所以a后面所有的 b 都出现了。 - 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );
使用非贪婪的数量词的正则表达式 ab*? ,匹配结果: a。
即使前面有 * ,但是 ? 决定了尽可能少匹配 b,所以没有 b。 - Python里数量词默认是贪婪的。
项目:基于requests和正则猫眼电影top100定向爬虫
本项目反爬策略
在头部加上Host和Cookie信息
cookie 位置:右击 审查元素–>网络–>Headers
headers = {
'User-Agent': ua.random,
'Host': 'maoyan.com',
'Cookie': '__mta=244103482.1586583849431.1586591578863.1586591596622.7; uuid_n_v=v1; uuid=70A8E5507BB711EA904101D407E7401D56771E011B5248CCB28F41E623827FA2; _csrf=911258e83ffafda305001ded783784bef80e9113d1d47c8f8b4940dc934b9acd; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586583838; mojo-uuid=1bf14bca5d2a510f6e85c2857cc8d257; _lxsdk_cuid=17167c43f33c8-07022459d688ce-4313f6a-144000-17167c43f33c8; _lxsdk=70A8E5507BB711EA904101D407E7401D56771E011B5248CCB28F41E623827FA2; mojo-session-id={"id":"83a8b6a56c45ba34bd30bd7e6d5c46b9","time":1586591446957}; __mta=244103482.1586583849431.1586583890672.1586591526586.6; mojo-trace-id=6; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586591597; _lxsdk_s=171683837b1-2a5-86f-f4e%7C%7C10'}
}
基于requests和正则猫眼电影top100定向爬虫code
使用多线程和多进程
def no_use_thread():
for page in range(1,11):
get_one_page(page)
print(Fore.GREEN+'[+]采集第%s页数据' %(page))
#反爬虫策略:速度太快被限速,在数据采集的过程中休眠几秒
time.sleep(1)
def use_multi_thread():
# 使用多线程实现
from threading import Thread
for page in range(1, 11):
# 开启多线程,每一页
thread = Thread(target=get_one_page, args=(page,)) # args是元组
thread.start()
print(Fore.GREEN + '[+]采集第%s页数据' % (page))
def use_thread_pool():
# 使用线程池实现
from concurrent.futures import ThreadPoolExecutor
# 实例化线程池 并指定线程池的线程个数
pool = ThreadPoolExecutor(100)
pool.map(get_one_page, range(1, 11))
print("采集结束")
if __name__ == '__main__':
use_multi_thread()
二、XPath数据解析库
lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。
XPath (XML Path Language) 是一门在 xml文档中查找信息的语言,可用来在 xml /html文档中对元素和属性进行遍历。
- XPath如何实现文档解析?
1、etree库把HTML文档中的字符串解析为Element对象
from lxml import etree
html=etree.HTML(text)
result=etree.tostring(html)
2、etree库把HTML文档解析为Element对象
html=etree.parse(‘xxx.html’)
result=etree.tostring(html,pretty_print=True)
常用规则:
2.xpath用法
from lxml import etree
text = """
<h1>标题一</h1>
<h2>标题二
"""
# 1. etree 把html文档中的字符串解析为Element对象
html = etree.HTML(text)
print(html) #<Element html at 0x17f7c47c808>
print(etree.tostring(html)) #b'<html><body><h1>标题一</h1>\n<h2>标题二\n</h2></body></html>'
# 2.
html = etree.parse('hello.html')
result = etree.tostring(html, pretty_print=True)
print(result)
项目:基于requests和XPath猫眼电影TOP100定向爬虫
页面分析
基于requests和XPath猫眼电影TOP100定向爬虫code
运行结果:
项目: 基于requests和XPath的TIOBE编程语言排行榜定向爬虫
基于requests和XPath的TIOBE编程语言排行榜定向爬虫code
页面分析:运行结果:生成tiobe.csv文件
这里涉及到CSV文件的读写操作:
import csv
# # 1. 通过reader方式读取文件内容,每行内容是一个列表
# with open('hello.csv') as f:
# csv_reader = csv.reader(f)
# for row in csv_reader:
# print(row) # 返回的是列表
#2. 通过Dictreader方式读取文件,每行是字典
# with open('hello.csv') as f:
# csv_reader = csv.DictReader(f)
# for row in csv_reader:
# print(row) # OrderedDict([('name', 'zhangsan'), ('age', '10')])
# print('名称:',row['name'])
# print('年龄:',row['age'])
# # 3. 通过writer写入文件,必须传入一个列表
# info = [
# ('zhangsan',10),
# ('lisi',20),
# ]
# with open('writer.csv','w',encoding='utf-8') as f:
# csv_writer = csv.writer(f)
# # 一次写入多行内容
# csv_writer.writerows(info)
# # for循环, 一次写入一行内容
# for row in info:
# csv_writer.writerow(row)
# 4. 通过DictWriter方式写入文件,必须传入一个字典
with open('writer.csv','w',encoding='utf-8') as f:
# 传两个值:文件名称,字典KEY值(表头)
csv_writer = csv.DictWriter(f,['name','password']) # 表头
for row in range(10):
csv_writer.writerow({
'name':'name'+str(row),
'password':'password'+str(row)
})
# for row in data:
# csv_writer.writerow(row)
三、BeautifulSoup数据解析库
Beautiful Soup 4.4.0是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
BS4基本用法
# 1. 从bs4模块中导入BeautifulSoup
from bs4 import BeautifulSoup
html = """
<h1> bs4 </h1>
"""
# 2.实例化BeautifulSoup对象,并通过指定的解析器(4种)解析html字符串的内容
soup = BeautifulSoup(html,'lxml') # 使用'lxml'解析器
result = soup.prettify()
print(result)
运行结果:
BS4的节点选择器代码
BS4的方法选择器代码
BS4的CSS选择器代码
项目:基于requests和BS4的三国演义名著定向爬虫
思路分析:
页面分析:
章节的页面:
基于requests和BS4的三国演义名著定向爬虫代码
运行结果: