网络爬虫与正则表达式

对应教学日历:讲次 14-15


一、网络爬虫概述

网络爬虫:按照一定规则,自动抓取万维网信息的程序或脚本。

爬虫步骤

  1. 获取网页源码
  2. 根据目标链接特点写出正则表达式
  3. 用正则对象匹配获取目标链接
  4. 用循环结构遍历目标链接并下载信息

二、requests 库

import requests

获取网页内容

url = "http://www.people.com.cn/"
r = requests.get(url)
r.encoding = r.apparent_encoding   # 修正编码
data = r.text                       # 字符串形式

Response 对象属性

属性说明
r.text网页响应内容的字符串形式
r.content网页响应内容的二进制形式
r.encoding猜测的编码方式
r.apparent_encoding从内容分析出的编码方式

爬取图片

import requests
url = "http://example.com/image.jpg"
r = requests.get(url)
data = r.content
with open("result.jpg", "wb") as fobj:
    fobj.write(data)

三、正则表达式(re模块)

import re

常用模式

模式描述
\d匹配一个数字字符
\w匹配字母、数字、下划线
\s匹配一个空白字符
.匹配任意字符(换行符除外)
{n}匹配n个字符
{n,m}匹配n到m个字符
*匹配前面的字符0次或多次
+匹配前面的字符1次或多次
?匹配前面的字符0次或1次
[]字符范围,只能取一个
( )构建一个组

基本示例

import re
content = 'Hello 123 world 456'
re.findall(r'\d\d\d', content)      # ['123', '456']
re.findall(r'\d{3}', content)       # ['123', '456']
re.findall(r'\w\w\w', content)      # ['Hel', '123', 'wor', '456']
re.findall(r'.o', content)          # ['lo', 'wo']
re.findall(r'\d{1,3}', content)     # ['12', '345', '6']
re.findall(r'\d*\d', content)       # ['12', '456', '3']
re.findall(r'\d+\d', content)       # ['12', '456']
re.findall(r'\d?\d', content)       # ['12', '45', '6', '3']

字符范围

content = 'Mike_123 sum  Hi_1234 456'
re.findall(r'[0-9a-zA-Z\_]{6,8}', content)
# ['Mike_123', 'Hi_1234']

组匹配

content = 'Hello 12 world 4567'
re.findall(r'\d(.*)\d', content)    # ['2 world 456']

四、贪婪匹配 vs 非贪婪匹配

import re
res = '文本A百度新闻文本B,文本A新浪财经文本B,文本A搜狐新闻文本B'
 
# 贪婪匹配(默认):尽可能多地匹配
re.findall(r'文本A(.*)文本B', res)
# ['百度新闻文本B,文本A新浪财经文本B,文本A搜狐新闻']
 
# 非贪婪匹配:尽可能少地匹配
re.findall(r'文本A(.*?)文本B', res)
# ['百度新闻', '新浪财经', '搜狐新闻']

非贪婪匹配在量词后加 ?.*?, +?, {n,m}?

五、re库内置函数

import re
string = "I love ECUST. ECUST loves me."
 
re.match("I", string)       # 从起始位置匹配
re.search("ECUST", string)  # 搜索第一个匹配
re.findall("ECUST", string) # 返回所有匹配列表
re.findall("it", string, re.I)  # re.I 忽略大小写

compile + re.I 实现不区分大小写

test = re.compile("it", re.I)
result = re.findall(test, string)
# ['It']

作业示例

爬取人民网链接和标题

import requests
import re
url = "http://www.people.com.cn"
r = requests.get(url)
r.encoding = r.apparent_encoding
data = r.text
reg = r'<li><a href="(.*?)" target="_blank">(.*?)</a></li>'
urls = re.findall(reg, data)
fobj = open("peoplecn.csv", 'w', encoding="GBK")
for titu in urls:
    fobj.write(titu[0] + "," + titu[1] + '\n')
fobj.close()

要点

  • (.*?) 非贪婪匹配提取内容
  • findall 返回元组列表 [(url, title), ...]

爬取新闻图片

import requests
import re
url = 'http://www.people.com.cn'
r = requests.get(url)
r.encoding = r.apparent_encoding
paper = r.text
regrule = r' target=_blank><img src="(.*?)"'
urls = re.findall(regrule, paper)
x = 0
for imgu in urls:
    r = requests.get(url + imgu)
    filename = '%d.jpg' % x
    with open(filename, 'wb') as f:
        f.write(r.content)
    x += 1

HTML标签提取

import re
s = '''<img src="C:\\XH.jpg" width="300"/>
<img src="C:\\FX.jpg" width="300"/>'''
result = re.findall(r'<img src="(.*?)" ', s)
print(result)  # ['C:\\XH.jpg', 'C:\\FX.jpg']
 
# 提取多个属性
result = re.findall(r'<img src="(.*?)" width="(.*?)"', s)
print(result)  # [('C:\\XH.jpg', '300'), ('C:\\FX.jpg', '300')]

不区分大小写匹配

import re
result = re.compile("it", re.I)
string = "I love it. It loves me."
re.findall(result, string)  # ['it', 'It']

作业重点

  • requests.get(url) 获取网页,r.text 返回字符串
  • r.encoding = r.apparent_encoding 修正编码方式
  • \d 数字、\w 字母数字下划线、. 任意字符
  • {n} 精确匹配n次、{n,m} 匹配n到m次
  • * 0次或多次、+ 1次或多次、? 0次或1次
  • (.*?) 非贪婪匹配提取内容,(.*) 贪婪匹配
  • re.findall(pattern, string) 返回所有匹配的列表
  • re.I 忽略大小写修饰符
  • 爬虫核心:获取源码 → 正则匹配 → 提取目标