前言
例如:爬虫技术基础--正则表达式。 用python模仿人点击浏览器,让web站点无法发现不是人。 反爬机制更新,程序失效。 python请求模块、解析模块丰富成熟,强大的scrapy网络爬虫框架。 1.通用网络爬虫:搜索引擎在用,遵守robots协议。百度快照是百度抓取的。 2.聚焦网络爬虫:面向需求,自己写的爬虫程序。一、爬虫爬取步骤
1.确定URL地址 2.请求模块,得到网站的响应(网页源码) 3.从响应内容中提取自己需要的数据二、请求模块
1.模块名:urllib.request 2.导入方式:res.read()结果是byte结构类型,res.read().decode('utf-8')是字符串类型import urllib.request
或
from urllib import request
req = request.Request(url,headers=headers)
res = request.urlopen(req)
html = res.read().decode('utf-8')
3.headers
在谷歌地址栏输入 about:version,得到headers信息。才能获得真正的源代码。
代码如下:
import requests
import re
ur1 = "https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&ie=utf-8&word=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4"
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36'}
res = requests.get(ur1, headers = headers).text
p_info = '<p class="c-author">(.*?)</p>'
info = re.findall(p_info, res)
print(info)
4.从包引入headers
代码如下:
from fake_useragent import UserAgent
ua = UserAgent()
ua1 = ua.random
print(ua1)
三、编码模块
1.parse
urlencode({dict})
urlencode({'wd':'美女','pn':'20'})
# 编码后:'wd=%E8%D5XXX&PN=20'
from urllib import parse
params = {'wd':'赵丽颖'}
result = parse.urlencode(params)
url = 'https://www.baidu.com/s?' + result
print(result)
print(url)
#拼接url地址
#赵丽颖第二页
params = {'wd':'赵丽颖','pn':'10'}
result = parse.urlencode(params)
url = 'https://www.baidu.com/s?' + result
print(result)
print(url)
#url地址拼接
#1.字符串拼接:见上
#2.字符串格式化:用占位符实现
params = 'wd=%E7XXXX&pn=20'
url = 'https://www.baidu.com/s?%s'% params
print(url)
#3.format用法
url = 'https://www.baidu.com/s?{}'
params = 'wd=%E7XXXX&pn=20'
url = url.format(params)
print(url)
2.quote:
from urllib import parse
word = '美女'
result = parse.quote(word)
url = 'https://www.baidu.com/s?wd' + result
print(url)
baseurl = 'https://www.baidu.com/s?wd={}'
url = baseurl.format(result)
print(url)
3.解码:
unquote('%D3%F5XXX')
四、正则解析模块
1.re模块使用流程
import re
# r_list = re.findall('AB','ABCABCABCD')
# print(r_list)
# #(re.findall(pattern, string, flags=0)):返回string中所有与pattern相匹配的全部字符串,得到数组
# #['AB', 'AB', 'AB']
pattern = re.compile('AB')
r_list = pattern.findall('ABCABCABCD')
print(r_list)
2.写出匹配任意一个字符的正则表达式(两种方法)常用方法一
import re
pattern1 = re.compile('.',re.S)
pattern2 = re.compile('[\s\S]')
3.创建正则表达式(两种方法)常用方法二
import re
r_list = re.findall('正则表达式',html,re.S)
import re
pattern = re.compile(r'正则表达式',re.S)
r_list = pattern.findall(html)
输出结果是字符串,不是数字。
import re
content = 'hello 123 world 456 python基础135‘
result = re.findall('\d\d\d', content)
print(result)
符号 | 功能说明 |
---|---|
\d | 匹配一个数字字符 |
\w | 匹配一个字母、数字、或者下划线字符 |
\s | 匹配一个空白字符,e.g.换行符、制表符、普通空格 |
\S | 匹配一个非空白字符 |
\n | 匹配一个换行符,相当于按一次enter |
\t | 匹配一个制表符,相当于按一次tab,或者8次空格 |
. | 匹配一个任意字符,换行符除外 |
* | 匹配0个或多个表达式 |
+ | 匹配1个或多个表达式 |
? | 非贪婪限定符 |
() | 匹配括号内的表达式 |
五、贪婪匹配–(.*?)/非贪婪匹配
1.贪婪匹配
(.*?)
1.在整个表达式匹配成功的前提下,尽可能多的匹配 * + ?
2. 表示方式: .* .+ .?
用于获取文本A和文本B之间的所有内容
代码如下:
import re
res = '文本A百度新闻文本B,新闻标题文本A新浪财经文本B,文本A搜狗新闻文本B'
p_source = '文本A(.*?)文本B'
source = re.findall(p_source, res)
print(source)
2.非贪婪匹配
(.*?)
1.在整个表达式匹配成功的前提下,尽可能少的匹配 * + ?
2. 表示方式: .*? .+? .??
代码如下:
import re
pattern = re.compile('<div><p>.*?</p></div>',re.S)
r_list = pattern.findall(html)
print(r_list)
括号里放想要的内容,去掉 div> p>
import re
pattern = re.compile('<div><p>(.*?)</p></div>',re.S)
r_list = pattern.findall(html)
print(r_list)
s = 'A B C D'
p1 = re.compile('\w+\s+\w+')
print(p1.findall(s))
# 结果:['A B', 'C D']
p2 = re.compile('(\w+)\s+\w+')
print(p2.findall(s))
# 结果:
# 第一步:匹配完整['A B', 'C D']
# 第二步:匹配()中['A', 'C']
p3 = re.compile('(\w+)\s+(\w+)')
print(p3.findall(s))
# 结果:
# 第一步:匹配完整['A B', 'C D']
# 第二步:匹配()中[('A', 'B'), ('C', 'D')]
# 如果正则表达式中有两个以上元素,得到的是元祖套列表
六、实现步骤
1.查看是否为静态页面
右键-查看网页源代码-搜索数据关键字
2.找URL规律
第一页:http://tieba.baidu.com/f?kw=??&pn=0
第二页:http://tieba.baidu.com/f?kw=??&pn=50
第n页:pn=(n-1)*50
3.获取网页内容
4.提取所需数据
写正则表达式,来匹配数据
5.程序结构
1.使用随机User-Agent
2.每爬取1个页面后随机休眠一段时间
5.保存(本地文件、数据库)
import urllib.request
或
from urllib import request
七、练习-爬取百度贴吧
1.方法一代码示例
from urllib import request,parse
import random
import time
from useragents import ua_list
class TiebaSpider(object):
def __init__(self):
self.url = 'http://tieba.baidu.com/f?kw={}&pn={}'
#获取响应内容
def get_page(self,url):
headers = {'User-Agent': random.choice(ua_list)}
req = request.Request(url=url,headers=headers)
res = request.urlopen(req)
html = res.read().decode()
return html
#解析,提取数据
def parse_page(self):
pass
#保存数据
def write_page(self,filename,html):
with open(filename,'w') as f:
f.write(html)
#入口函数
def run(self):
name = input('请输入贴吧名:')
start = int(input('请输入贴吧起始页:'))
end = int(input('请输入贴吧终止页:'))
kw = parse.quote(name)
#拼接+获取内容+保存
for i in range(start,end+1):
pn=(i-1)*50
url = self.url.format(kw,pn)
html = self.get_page(url)
filename = '{}-第{}页.html'.format(name,i)
self.write_page(filename,html)
print('第%d页抓取成功'%i)
#每爬取1个页面随机休眠1-3秒
time.sleep(random.randint(1,3))
if __name__=='__main__':
begin = time.time()
spider = TiebaSpider()
spider.run()
stop = time.time()
print('执行时间:%.2f' % (stop-begin))
2.方法二
#使用fake_useragent模块实现
from urllib import request,parse
import random
import time
from fake_useragent import UserAgent
class TiebaSpider(object):
def __init__(self):
self.url = 'http://tieba.baidu.com/f?kw={}&pn={}'
def get_headers(self):
ua = UserAgent()
headers = {'User-Agent':ua.random}
return headers
#获取响应内容
def get_page(self,url):
headers = self.get_headers()
#验证每一步的user agent不同
#print(headers)
req = request.Request(url=url,headers=headers)
res = request.urlopen(req)
html = res.read().decode()
return html
#解析,提取数据
def parse_page(self):
pass
#保存数据
def write_page(self,filename,html):
with open(filename,'w') as f:
f.write(html)
#入口函数
def run(self):
name = input('请输入贴吧名:')
start = int(input('请输入贴吧起始页:'))
end = int(input('请输入贴吧终止页:'))
kw = parse.quote(name)
#拼接+获取内容+保存
for i in range(start,end+1):
pn=(i-1)*50
url = self.url.format(kw,pn)
html = self.get_page(url)
filename = '{}-第{}页.html'.format(name,i)
self.write_page(filename,html)
print('第%d页抓取成功'%i)
#每爬取1个页面随机休眠1-3秒
time.sleep(random.randint(1,3))
if __name__=='__main__':
begin = time.time()
spider = TiebaSpider()
spider.run()
stop = time.time()
#计算程序执行时间
print('执行时间:%.2f' % (stop-begin))
八、练习-动物
代码如下:
import re
html = '''
<div class="animal">
<p class="name">
<a title="Tiger"></a>
</p>
<p class="content">
Two tigers two tigers run fast
</p>
</div>
<div class="animal">
<p class="name">
<a title="Rabbit"></a>
</p>
<p class="content">
Small white rabbit white and white
</p>
</div>
'''
# 去掉<div><p>,想要的内容放括号里
pattern = re.compile('<div class="animal">.*?title="(.*?)".*?"content">\n\s+(.*?)\n\s+</p>',re.S)
r_list = pattern.findall(html)
print(r_list)
# p3 = re.compile('(\w+)\s+(\w+)')
# print(p3.findall(s))
# 结果:
# 第一步:匹配完整['A B', 'C D']
# 第二步:匹配()中[('A', 'B'), ('C', 'D')]
# 如果正则表达式中有两个以上元素,得到的是元祖套列表
print("动物名称:" + r_list[0][0])
print("动物描述:" + r_list[0][1])
print("动物名称:" + r_list[1][0])
print("动物描述:" + r_list[1][1])
更优:
import re
html = '''
<div class="animal">
<p class="name">
<a title="Tiger"></a>
</p>
<p class="content">
Two tigers two tigers run fast
</p>
</div>
<div class="animal">
<p class="name">
<a title="Rabbit"></a>
</p>
<p class="content">
Small white rabbit white and white
</p>
</div>
'''
re_bds = '<div class="animal">.*?title="(.*?)".*?'\
'class="content">(.*?)</p>'
pattern = re.compile(re_bds,re.S)
r_list = pattern.findall(html)
print(r_list)
for r in r_list:
print("动物名称:" + r[0].strip())
print("动物描述:" + r[1].strip())
print('*'*50)
总结
以上仅是爬虫基础的内容,简单介绍了爬虫的使用,后续将在应用中继续学习。