31.爬虫一
Posted liuzhanghao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了31.爬虫一相关的知识,希望对你有一定的参考价值。
request模块:
- request模块的基本使用
- python中封装好的一个基于网络亲求的模块
- requests模块的作用
- 用来模拟浏览器发送请求
- requests的环境安装
- pip install request
- request模块的编码流程:
- 1指定url
- 2发起请求
- 3获取相应数据
- 4持久化存储
# 爬取搜狗首页页面的源码数据
import requests
# 1.指定url
url = ‘https://www.sogou.com‘
# 2.发起请求
response = requests.get(url=url)
# 3.获取响应对象
page_text = response.text
# page_text
# with open(‘sogou.html‘, "w", encoding=‘utf-8‘) as f:
# f.write(page_text)
# 实现一个建议的网页采集器
# 需要让url携带的参数动态化
url = ‘https://www.sogou.com/web/‘
# 实现参数动态化
wd = input("enter a key:")
params = {
"query": wd,
}
# 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
page_txt = requests.get(url,params=params).text
page_txt
文件乱码:
- 上面带请求数据出现错误
- 文件乱码
- 没有拿到数据
# 实现一个建议的网页采集器
# 需要让url携带的参数动态化
url = ‘https://www.sogou.com/web/‘
# 实现参数动态化
wd = input("enter a key:")
params = {
"query": wd,
}
# 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
response = requests.get(url,params=params)
response.encoding = ‘utf-8‘
page_txt=response.text
# page_txt
反爬机制:
- UA检测:检测到request发送的请求载体的身份表示不是浏览器
- Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36
# 结局UA检测
# 实现一个建议的网页采集器
# 需要让url携带的参数动态化
import requests
url = ‘https://www.sogou.com/web‘
# 实现参数动态化
wd = input("enter a key:")
params = {
"query": wd,
}
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
}
# 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
response = requests.get(url=url,params=params,headers=headers)
response.encoding = ‘utf-8‘
page_txt=response.text
# page_txt
动态加载数据爬取
# 爬取的是豆瓣电影的详情数据
# 当滚轮话单下面的时候动态加载数据
# 动态加载的数据
# 通过另一单独请求拿到的
# url = "https://movie.douban.com/explore#!type=movie&tag=%E7%88%B1%E6%83%85&sort=recommend&page_limit=20&page_start=0"
import requests
# url = "https://movie.douban.com/j/chart/top_list"
url = "https://movie.douban.com/j/search_subjects"
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
}
start = input("请输入开始页:")
end = input("请输入结束页:")
# dic = {
# "type": "13",
# "interval_id": "100:90",
# "action": "",
# "start": start,
# "limit": end,
# }
dic = {
"type":"movie",
"tag":"爱情",
"sort":"recommend",
"page_limit":start,
"page_start":end,
}
response = requests.get(url=url,params=dic,headers=headers)
data = response.json() # 返回json格式的数据对象
data
# for item in data["subjects"]:
# print(item["title"] + item["rate"] + str(len(data["subjects"])))
# 肯德基餐厅查询数据获取
import requests
url = "http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
}
data = {
"cname": "",
"pid": "",
"keyword": "北京",
"pageIndex":"1",
"pageSize": "10",
}
response = requests.post(url=url,headers=headers,data=data)
data = response.json()
# data
- 需求分析
- 爬取药监总局中相关企业的详情信息
- 如何检测页面中是否存在动态加载的数据?
- 基于抓包工具
- 先捕获网站请求后的所有的数据包
- 在数据包中定位到地址栏所对应请求的数据包,在response选项卡对应的数据中进行局部搜索(页面中的某一组内容)
- 可以搜索到:爬取道的不是动态加载的
- 搜索不到:爬取到的数据是动态加载的
- 如何进行动态加载数据在那个数据包中?
- 进行全局搜索
# 页面数据接口获取
- 需求
- 爬取药监局总局中相关企业的http://125.35.6.84:81/zk/
- 需求分析
- 指定页面中企业相关数据是否为动态加载?
- 相关企业信息是动态加载出来的
- 通过抓包工具全局搜索,定位动态数据加载。
- post:http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList
- 请求返回的响应数据是一组json串,通过对json串的简单解析,没有找到企业详情页的url,但是找到每一个加企业的id
- 每一家企业详情页的url,域名都是一样的,只有请求参数id值不同
- 可以使用同一个域名结合这不同的id值拼接成一家完整企业详情页url
- 判断企业详情页中的数据是否为动态加载?
- 通过抓包工具检测,发现企业详情信息在详情页中为动态加载
- 通过抓包工具进行全局搜索,找到数据对应的url
- url:post:http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById
- 请求参数:id: b4437b636b5944eb9eadc1418f312b19
- 请求到的json串就是我们最终想要的企业详细数据
import requests
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
}
url = "http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList"
data1 = {
"on": "true",
"page": "1",
"pageSize": "15",
"productName":"",
"conditionType": "1",
"applyname":"",
"applysn":"",
}
response = requests.post(url=url,headers=headers,data=data1)
data = response.json()
for item in data["list"]:
url2 = "http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById"
data2 = {
"id": item["ID"]
}
response2 = requests.post(url=url2, headers=headers,data=data2).json()
# print(response2["businessPerson"]+ response2["legalPerson"])
回顾:
- requests作用:模拟浏览器发起请求
- urllib被requests替代了
- request模块的编码流程:
- 指定url
- 发起请求
- get(url,params,headers)
- post(url, headers, data)
- 获取响应数据
- 持久化存储
- 参数动态化
- 有些情况下我们是需要将请求参数进行更改,将get或者post请求对应的请求参数封装到一个字典(键值对)中,然后将字典作用到get方法的params参数中或者作用到post发放的data参数中
- UA检测(反爬机制)
- 什么是UA:请求载体的身份表示,服务器端会检测请求的UA来鉴定身份
- 反爬机制:UA伪装,通过抓包工具捕获某一浏览器的UA值,封装到字典中,且将该字典作用到headers参数中
- 动态加载数据
- 通过另一个单独的请求到的数据
- 如果我们要对一个陌生的网站进行指定数据的爬取?
- 首先要确定爬取的数据在该网站中是否为动态加载的
- 是:通过抓包工具实现全局搜索,定位动态家在数据对应的数据包,从数据包中提取请求的url和请求参数
- 不是:通过抓包工具对请求中的所有url响应进行搜索
正则,xpath,bs4:
### 今日内容
- 数据解析
- 数据解析的作用
- 可以帮助我们实现聚焦爬虫
- 数据解析的实现方式
- 正则
- bs4
- xpath(通用)
- pyquery
- 数据解析的通用原理
- 问题1:聚焦爬虫爬取的数据是存在哪里?
- 都被存储在标签之中和相关标签的属性中
- 1.定位标签
- 2.取文本后者属性
import requests
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
}
# 如何爬取图片
url = "https://pic.qiushibaike.com/system/pictures/12296/122968969/medium/LSG56EWMA84YO922.jpg"
img_data = requests.get(url=url, headers=headers).content
# with open("./img.jpg","wb") as f:
# f.write(img_data)
# 方式二
# 不可以使用UA伪装
from urllib import request
url = "https://pic.qiushibaike.com/system/pictures/12296/122968969/medium/LSG56EWMA84YO922.jpg"
# request.urlretrieve(url,filename="./qiushi.jpg")
正则解析:
<a class="recmd-left multi" href="/article/122969075" rel="nofollow" target="_blank" onclick="_hmt.push([‘_trackEvent‘,‘web-list-multi‘,‘chick‘])">
<img src="//qiubai-video-web.qiushibaike.com/article/gif/RP2LJ8DOWG2TVP7T.jpg?imageView2/1/w/150/h/112" alt="一直给女友吹嘘我厨艺">
<div class="recmd-tag">1图</div>
</a>
ex = ‘<a class="recmd-left.*?<img src="(.*?)" alt=.*?</a>‘
# 正则(麻烦)
# 糗事百科图片爬取1-3页所有的图片
# 设置一个通用的url模板(不可变)
import re
import os
if not os.path.exists("./imgLibs"):
os.mkdir(‘imgLibs‘)
url = "https://www.qiushibaike.com/8hr/page/%d/"
ex = ‘<a class="recmd-left.*?<img src="(.*?)?.*?" alt=.*?</a>‘
for i in range(1,4):
new_url = format(url%i)
img_data = requests.get(url=new_url, headers=headers).text
img_list = re.findall(ex, img_data,re.S)
for src in img_list:
src = "https:" + src
img_name = src.split("/")[-1]
img_path = "imgLibs/" + img_name
request.urlretrieve(src, img_path)
b64:
- bs4解析
- bs4解析的原理
- 实例化一个Beautifulsoup的对象,需要将即将被解析的页面源码数据加载到该对象中
- 调用BeautifulSoup对象中的想过方法和属性进行标签定位和数据提取
- 环境安装
- pip install bs4
- pip install lxml
- BeautifulSoup的实例化
- BeautifulSoup(fp,‘lxml‘),将背地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中
- BeautifulSoup(page_text, "lxml"),将从互联网上获取到的页面源码数据加载到实例化好的BeautifulSoup对象中
- 定位标签的操作
- soup.tagName:定位第一个出现的tagName标签
- 属性定位:soup.find("tagName", attrName=‘value‘)
- 属性定位:soup.find_all("tagName", attrName=‘value‘) # 返回列表
- 选择器定位:soup.select(‘选择器‘) # 返回一个列表
- 层级选择器:>表示一个层级,空格代表多个层级
- 取文本
- .sting:只可以获取直系的文本内容
- .text:
- 去属性
- [‘属性名称‘]
from bs4 import BeautifulSoup
fp = open("./test.html", "r", encoding="utf-8")
soup = BeautifulSoup(fp, "lxml")
soup.div
soup.find("div", class_="song")
soup.find("a", id="feng" )
soup.find_all("div", class_="song")
soup.select(‘.song‘)
soup.select(‘.tang > ul > li‘)
soup.select(‘.tang li‘)
a_tag = soup.select(‘#feng‘)[0]
a_tag.text
div = soup.div
div.string
div = soup.find(‘div‘,class_=‘song‘)
div.string
a_tag = soup.select(‘#feng‘)[0]
a_tag["href"]
# 爬取三国整片内容
from bs4 import BeautifulSoup
fp = open("./sanguo.txt",‘w‘,encoding="utf-8")
page_url = "http://www.shicimingju.com/book/sanguoyanyi.html"
page_text = requests.get(url=page_url, headers=headers).text
soup = BeautifulSoup(page_text, "lxml")
a_list = soup.select(‘.book-mulu > ul > li > a‘) # 返回的列表中存储的是一个个li标签
for a in a_list:
title = a.string
detail_url = "http://www.shicimingju.com" + a[‘href‘]
detail_page_text = requests.get(url=detail_url, headers=headers).text
# 解析详情页中的章节内容
soup1 = BeautifulSoup(detail_page_text, "lxml")
content = soup1.find(‘div‘, class_=‘chapter_content‘).text
# fp.write(title + ":" + content + "
")
# print(title, "下载成功")
# # print("over")
xpath:
- xpath解析
- xpath解析实现的原理
- 1.实例化一个etree对象,然后将即将被解析的页面源码加载到该对象中
- 2.使用etree对象中xpath方法结合这不同形式的xpath表达式实现标签定位和数据提取
- 环境安装
pip install lxml
- etree对象实例化
- etree.parse(‘test.html‘)
- etree.HTML(page_text)
- xpath表达式
- 最左侧的/表示:xpath表达式一定要从跟标签逐层进行查找和定位
- 最左侧//表示:xpath表达式可以从任意位置定位标签
- 非最左侧的/:表示一个层级
- 非最左侧//表示:表示多个层级
- 属性定位://tagName[@attrName="value"]
- 索引定位:
- 取文本:
- /text() : 直系文本
- //text() : 所有的文本内容
- 取属性
- /@attrName
from lxml import etree
tree = etree.parse(‘./test.html‘)
tree.xpath(‘/html/head/title‘)
tree.xpath(‘//title‘)
tree.xpath(‘//dic[@class="song"]‘)
tree.xpath(‘//li[2]/text()‘)
tree.xpath("//li[2]/a/@href")
# 爬取糗事百科段子内的作者名称
import requests
from lxml import etree
url = "https://www.qiushibaike.com/text/"
page_text = requests.get(url=url, headers=headers).text
# 解析内容
tree = etree.HTML(page_text)
div_list = tree.xpath("//div[@class=‘col1 old-style-col1‘]/div")
for div in div_list:
author = div.xpath(‘./div[1]/a[2]/h2/text()‘)[0]
content = div.xpath(‘./a[1]/div/span/text()‘)
content = "".join(content)
# print(author,content)
合并条件:
# 合并xpath表达式,提高xpath的通用性
a.xpath("./b/text() | ./img/@src")
错误分析
- HttpConnectionPoll
- 原因:
- 短时间内发起了太多请求
- http连接池中的连接资源被耗尽
- 解决:
- 使用代理
- headers中加入Conection:"close"
以上是关于31.爬虫一的主要内容,如果未能解决你的问题,请参考以下文章