爬虫 第二天
回顾
- 问题:
- ip被封:代理
- 请求参数问题:
- 动态变化的请求参数
- 加密的请求参数
- 响应数据的问题:
- cookie
- 请求参数
- 加密:
- js逆向
- 重点内容
- 参数的动态化
- data/prames
- 反爬机制:
- robots.txt
- UA检测
- 动态加载的数据
- 如何检测数据是否为动态加载
- 如何捕获动态加载的数据
- 动态加载的数据是如何生成?
- ajax
- js
- 参数的动态化
数据解析
- 作用:实现聚焦爬虫
- 实现方式:
- 正则
- bs4:重点
- xpath:重点
- pyquery:自学
- 数据解析的通用原理是什么?
- 解析的一定是html页面的源码数据
- 标签中存储的文本内容
- 标签属性的属性值
- 原理:
- 标签定位
- 取文本或者取属性
- 解析的一定是html页面的源码数据
- 爬虫实现的流程
- 指定url
- 发请求
- 获取响应数据
- 数据解析
- 持久化存储
In [2]:
import requests
import re
headers = {
#需要修改的请求头信息
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
正则解析
单字符: . : 除换行以外所有字符 [] :[aoe] [a-w] 匹配集合中任意一个字符 \d :数字 [0-9] \D : 非数字 \w :数字、字母、下划线、中文 \W : 非\w \s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 \S : 非空白 数量修饰:
* : 任意多次 >=0
+ : 至少1次 >=1
? : 可有可无 0次或者1次
{m} :固定m次 hello{3,}
{m,} :至少m次
{m,n} :m-n次
边界:
$ : 以某某结尾
^ : 以某某开头
分组:
(ab)
贪婪模式: .*
非贪婪(惰性)模式: .*?
re.I : 忽略大小写
re.M :多行匹配
re.S :单行匹配
re.sub(正则表达式, 替换内容, 字符串)
In [ ]:
import re
#提取出python
key="javapythonc++php"
#####################################################################
#提取出hello world
key="<html><h1>hello world<h1></html>"
#####################################################################
#提取170
string = '我喜欢身高为170的女孩'
#####################################################################
#提取出http://和https://
key='http://www.baidu.com and https://boob.com'
#####################################################################
#提取出hit.
key='[email protected]'#想要匹配到hit.
#####################################################################
#匹配sas和saas
key='saas and sas and saaas'
#####################################################################
In [3]:
key="javapythonc++php"
re.findall('python',key)
Out[3]:
['python']
In [4]:
#提取出hello world
key="<html><h1>hello world<h1></html>"
re.findall('<h1>(.*?)<h1>',key)
Out[4]:
['hello world']
In [6]:
#提取170
string = '我喜欢身高为170的女孩'
re.findall('\d+',string)
Out[6]:
['170']
In [11]:
#提取出http://和https://
key='http://www.baidu.com and https://boob.com'
re.findall('https?://',key)
Out[11]:
['http://', 'https://']
In [13]:
#提取出hit.
key='[email protected]'#想要匹配到hit.
re.findall('h.*?\.',key)
Out[13]:
['hit.']
In [14]:
#匹配sas和saas
key='saas and sas and saaas'
re.findall('sa{1,2}s',key)
Out[14]:
['saas', 'sas']
- 需求:使用正则将http://duanziwang.com/category/%E6%90%9E%E7%AC%91%E5%9B%BE/ 对应的段子的标题取出
In [16]:
url = 'http://duanziwang.com/category/搞笑图/'
#捕获到的是字符串形式的响应数据
page_text = requests.get(url=url,headers=headers).text
#数据解析
ex = '<div class="post-head">.*?<a href="http://duanziwang.com/\d+\.html">(.*?)</a></h1>'
re.findall(ex,page_text,re.S)#爬虫使用正则做解析的话re.S必须要使用
#持久化存储
Out[16]:
['比较下老婆和老妈,一比吓一跳_段子网收录最新段子',
'搞笑夫妻:烦恼里面找快乐_段子网收录最新段子',
'夫妻界的搞笑奇葩_段子网收录最新段子',
'超囧冷人小夫妻_段子网收录最新段子',
'雷人夫妻:吃泡面、偷看日记和生日送花_段子网收录最新段子',
'脸皮薄的人难以成功_段子网收录最新段子',
'12秒的雷政富和21秒李小璐_段子网收录最新段子',
'从前有只麋鹿,它在森林里玩儿,不小心走丢了。于是它给它的好朋友长颈鹿打电话:“喂…我迷路啦。”长颈鹿听见了回答说:“喂~我长颈鹿啦~”_段子网收录最新段子',
'最萌挡车球_段子网收录最新段子',
'再高贵冷艳的喵星人! 也总有一天有被吓得屁滚尿流的时候。_段子网收录最新段子']
bs4解析
- 环境安装:
- pip install bs4
- pip install lxml
- 解析原理
- 1.实例化一个BeautifulSoup的对象,需要将等待被解析的页面源码数据加载到该对象中
- 2.需要调用BeautifulSoup对象中相关的属性和方法进行标签定位和文本数据的提取
- BeautifulSoup如何实例化
- 方式1:BeautifulSoup(fp,'lxml'),将本地存储的一张html文件中的指定数据进行解析
- 方式2:BeautifulSoup(page_text,'lxml'),将从互联网中爬取到的数据直接进行数据解析
- 标签定位
- soup.tagName:定位到第一个出现的tagName标签
- 属性定位:根据指定的属性进行对应标签的定位
- soup.find('tagName',attrName='value')
- soup.find_all('tagName',attrName='value')
- 选择器定位:
- soup.select('选择器')
- 层级选择器:
- 大于号:表示一个层级
- 空格:表示多个层级
- 取文本
- tag.string:取出直系的文本内容
- tag.text:取出所有的文本内容
- 取属性
- tag['attrName']
In [18]:
from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
soup
In [28]:
soup.div
# soup.find('div',class_='song')
# soup.find('a',id='feng')
# soup.find_all('div',class_='song')
# soup.select('.tang')
# soup.select('#feng')
soup.select('.tang li')
In [38]:
soup.p.string
soup.p.text
soup.find('div',class_='tang').text
a_tag = soup.select('#feng')[0]
a_tag['href']
Out[38]:
'http://www.haha.com'
- 将三国演义整片小说内容进行爬取且持久化存储
- http://www.shicimingju.com/book/sanguoyanyi.html
In [44]:
main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=main_url,headers=headers).text
fp = open('./sanguo.txt','w',encoding='utf-8')
#数据解析
soup = BeautifulSoup(page_text,'lxml')
#解析出章节的标题&详情页的url
a_list = soup.select('.book-mulu > ul > li > a')
for a in a_list:
title = a.string
detail_url = 'http://www.shicimingju.com'+a['href']
#捕获章节内容
page_text_detail = requests.get(detail_url,headers=headers).text#获取了详情页的页面源码数据
#数据解析:章节内容
detail_soup = BeautifulSoup(page_text_detail,'lxml')
div_tag = detail_soup.find('div',class_='chapter_content')
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'下载成功!!!')
fp.close()
- 图片数据的爬取
- 基于requests
- 基于urllib
- 区别:能不能实现UA伪装
In [47]:
#基于requests
url = 'http://pic.netbian.com/uploads/allimg/190902/152344-1567409024af8c.jpg'
img_data = requests.get(url=url,headers=headers).content#content返回的是二进制类型的数据
with open('./123.png','wb') as fp:
fp.write(img_data)
In [49]:
#基于urllib
from urllib import request
request.urlretrieve(url=url,filename='./456.jpg')
Out[49]:
('./456.jpg', <http.client.HTTPMessage at 0x217a8af3470>)
xpath解析
- 环境安装:
- pip install lxml
- 解析原理
- 实例化一个etree的对象,且将被解析的页面源码数据加载到该对象中
- 使用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据的提取
- 实例化对象:
- etree.parse('filePath'):将本地存储的一个html文件中的数据加载到实例化好的etree对象中
- etree.HTML(page_text)
- xpath表达式
- 标签定位:
- 最左侧的/:必须从根节点开始定位标签(几乎不用)
- 非最左侧的/:表示一个层级
- 最左侧的//:可以从任意位置进行指定标签的定位(最常用)
- 非最左侧的//:表示多个层级
- 属性定位://tagName[@attrName="value"]
- 索引定位://tagNamne[index],索引是从1开始
- //div[contains(@class, "ng")]
- //div[starts-with(@class, "ta")]
- 取文本
- /text():取出直系的文本内容
- //text():取出的是所有的文本
- 取属性
- /@attrName
- 标签定位:
In [76]:
from lxml import etree
tree = etree.parse('./test.html')
tree.xpath('/html/head/meta')
tree.xpath('/html//meta')
tree.xpath('//meta')
tree.xpath('/meta')#error
tree.xpath('//p')
tree.xpath('//div[@class="tang"]')
tree.xpath('//li[1]')
tree.xpath('//a[@id="feng"]/text()')[0]
tree.xpath('//div[@class="tang"]//text()')
tree.xpath('//a[@id="feng"]/@href')
Out[76]:
['http://www.haha.com']
- 需求:使用xpath解析图片地址和名称且将图片进行下载保存到本地
- http://pic.netbian.com/4kmeinv/
重点:局部解析的时候./表示的含义
In [86]:
import os
In [88]:
url = 'http://pic.netbian.com/4kmeinv/'
page_text = requests.get(url=url,headers=headers).text
dirName = 'imgLibs'
if not os.path.exists(dirName):
os.mkdir(dirName)
#数据解析
tree = etree.HTML(page_text)
#xpath是基于一整张页面源码进行数据解析
img_list = tree.xpath('//div[@class="slist"]/ul/li/a/img')
#局部数据解析
for img in img_list:
#./表示的是当前标签,xpath的调用者就是当前标签
img_src = 'http://pic.netbian.com'+img.xpath('./@src')[0]
img_name = img.xpath('./@alt')[0]+'.jpg'
img_name = img_name.encode('iso-8859-1').decode('gbk')
filePath = './'+dirName+'/'+img_name
request.urlretrieve(img_src,filename=filePath)
print(img_name,'下载成功!!!')
In [90]:
#全站操作
#1.指定一个通用的url模板:用来生成不同页码对应的url,模板是不可变
url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
dirName = 'imgLibs'
if not os.path.exists(dirName):
os.mkdir(dirName)
for pageNum in range(1,6):
if pageNum == 1:
page_url = 'http://pic.netbian.com/4kmeinv/'
else:
page_url = format(url%pageNum)
page_text = requests.get(url=page_url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
#xpath是基于一整张页面源码进行数据解析
img_list = tree.xpath('//div[@class="slist"]/ul/li/a/img')
#局部数据解析
for img in img_list:
#./表示的是当前标签,xpath的调用者就是当前标签
img_src = 'http://pic.netbian.com'+img.xpath('./@src')[0]
img_name = img.xpath('./@alt')[0]+'.jpg'
img_name = img_name.encode('iso-8859-1').decode('gbk')
filePath = './'+dirName+'/'+img_name
request.urlretrieve(img_src,filename=filePath)
print(img_name,'下载成功!!!')
In [ ]: