gridview ashx实现数据更新_爬虫基础(动态加载,数据解析)

爬虫基础

目录:

requests

  • 请求操作
  • 数据解析
  • 高级操作
    • 代理
    • cookie
    • 模拟登陆
  • 异步爬虫
  • selenium
  • js逆向

scrapy

  • 常用操作

爬虫:通过编写程序让其模拟浏览器上网,去互联网中爬取数据的过程

爬虫的分类:

  • 通用爬虫
    • 爬取一整张页面源码数据
  • 聚焦爬虫
    • 爬取页面中局部的指定数据
    • 聚焦爬虫是建立在通用爬虫的基础之上
  • 增量式爬虫
    • 监测网站数据更新的情况.
  • 分布式爬虫

反爬机制

反反爬策略

  • robots协议:存在于服务器端的文本协议,协议中就指定好了网站中哪些数据能爬哪些数据不可以爬取

requests模块的基础

介绍:基于网络请求的一个模块

下载:

pip install requests

编码流程:

  • 指定url
  • 发起请求
  • 获取响应数据
  • 持久化存储

参数动态化

  • 异常的请求:不是通过浏览器发起的请求都是异常请求.
    • User-Agent:请求载体的身份标识
  • 反爬机制:UA检测
  • 反反爬策略:UA伪装

基础爬虫,例:爬取搜狗首页数据

import requests
url = "https://www.sogo.com/"

# 拿到响应数据
response = requests.get(url=url).text
print(response)

动态加载数据的爬取

判断是否动态加载数据

<br> (二维码自动识别)

进行局部搜索 ctrl+F

http://wap.kfc.com.cn (二维码自动识别)

对一个网站数据进行爬取前:

1.查看我们想要爬取的数据是否为动态加载

  • 如果页面中的数据不是可以直接通过地址栏的url爬取到的就为动态加载数据
  • 检测方式:通过抓包工具查看preview或者进行局部搜索

2.如何爬取动态加载的数据?

  • 基于抓包工具进行全局搜索,可以定位到动态加载数据对应的数据包
    • 从数据包中就能提取出url请求方式请求头
  • 动态加载数据的生成方式?
    • ajax请求
    • js请求

例:爬取肯德基网站的地址

肯德基:http://www.kfc.com.cn/kfccda/index.aspx

headers里面的数据就是UA伪装
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/85.0.4183.102 Safari/537.36'
}
# 爬取一到六页的数据
for index in range(1, 6):
    data = {
        'cname': '',
        'pid': '',
        "keyword": "河北",
        "pageIndex": index,
        "pageSize": "10"
    }
    # 拿出所有的数据,然后要table1里面的数据
    all_response = requests.post(url, headers=headers, data=data).json().get("Table1")
    # 循环拿出数据
    for response in all_response:
        addr = response.get("storeName")
        detail = response.get("addressDetail")
        print(addr, detail)

最后,打印出数据

龙口东 天河北路华标广场首层
新洋 河北路1629号
乐都汇 河北大街中段115号乐都汇商场一层
滨河 张家口滨河北路一、二层
河北路 塘沽区河北路5348号
明华 黄河北大街78号

51e9adb904dd64654c60bd5183eb39ce.png

7e7061a67b2a1f8953cc42cb76c41045.png

例:解决数据乱码

# 问题
# 爬取的数据出现了乱码
key = input('enter a key word:')
# 参数动态化
params = {
    'query':key
}
url = 'https://www.sogou.com/web'
# 动态指定请求的参数
response = requests.get(url=url,params=params)
# 修改响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
fileName = key+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
    fp.write(page_text)

例:多层爬虫,荣耀商店

荣耀店铺信息:https://m.vmall.com/help/hnrstoreaddr.htm ,爬取多层

思路:

1.查看详情页中的数据是否为动态加载? 发现数据为动态加载数据
2.捕获动态加载数据? 基于抓包工具进行全局搜索 从定位到的数据包中分析出:请求参数shopId为动态变化的
结论:首先先要获取每一家店铺的shopId,然后在进行店铺详情页的数据抓取
3.如何获取每一家店铺的shopId? 在首页捕获
import requests
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}
url = "https://openapi.vmall.com/mcp/offlineshop/getShopList"

json_data = {"portal":2,"lang":"zh-CN","country":"CN","brand":1,"province":"北京","city":"北京","pageNo":1,"pageSize":20}

# 注意:如果请求参数不是键值对,而是一个字典,则请求中一定要使用json参数
# 此时response是一个列表
response = requests.post(url, headers=headers, json=json_data).json().get("shopInfos")  
for res in response:
    id = res.get("id")
    # 现在我们拿到详情地址的url去爬到里面去
    # 因为每次访问不同的详情页的时候,shopid都会发生变化,所以给他一个动态参数
    detail_url = "https://openapi.vmall.com/mcp/offlineshop/getShopById?portal=2&version=10&country=CN&shopId=%d&lang=zh-CN" % id
    # url里面已经包含了params,所以不必重新构造一个params
    detail_res = requests.get(detail_url, headers=headers).json().get("shopInfo")
    print("地址:"+ res.get("name") +",营业时间:"+ detail_res.get("serviceTime"))
注意:如果请求参数不是键值对,而是一个字典,则请求中一定要使用json参数

打印效果:

地址:荣耀授权体验店(鑫海韵通电器商城店),营业时间:9:00-19:30
地址:荣耀授权体验店(西铁营中路店),营业时间:9:00-18:00
地址:荣耀授权体验店(大兴龙湖天街店),营业时间:10:00-22:00
地址:荣耀授权体验店(天通苑中苑店),营业时间:9:30-21:30
地址:荣耀授权体验店(丰科路店),营业时间:9:00-18:00

数据解析

1.re

  • 问题:浏览器的开发者工具中ELements和netword的response中都存放的是页面源码数据, 区别是什么?
  • 区别在于:Elements中显示的页面源码数据是经过全局渲染的,而response中仅仅是当前 一个请求响应回来的数据.如果页面中存在动态加载数据,则Elements中可以查看到动态 加载的数据,而response中查看不到
  • 站长素材图片爬取:
    • 反爬:图片懒加载:页面中使用伪属性替代真正的属性
    • 策略:可以在解析的时候,直接解析伪属性的值即可

例:爬取图片并保存本地(静态网页)

http://sc.chinaz.com/tupian/eluosi.html

两种方法爬取

# #图片爬取方式1:
# img_url = 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1593106255,4245861836&fm=26&gp=0.jpg'
# #content:返回的是二进制的数据
# img_data = requests.get(url=img_url,headers=headers).content
# with open('./123.png','wb') as fp:
#     fp.write(img_data)

# 方式2:urllib
# from urllib import request
# img_url = 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1593106255,4245861836&fm=26&gp=0.jpg'
# request.urlretrieve(img_url,filename='./456.png')
区别:方式1可以进行UA伪装,方式2不行

爬取

import requests
import os, re
from urllib import request
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}

url = "http://sc.chinaz.com/tupian/eluosi.html"

dirName = "mzlibs"
if not os.path.exists(dirName):
    os.mkdir(dirName)
# 要解析拿出图片的url
page_text = requests.get(url, headers=headers).text
#使用re进行图片链接的批量提取
ex = '<div>.*?<img src2="(.*?)" alt=.*?>.*?</div>'
# s = '''<div>
#     <a href="http://sc.chinaz.com/tupian/200811519845.htm" target="_blank" alt="清新氧气俄罗斯美女图片">
#     <img alt="清新氧气俄罗斯美女图片" src="http://pic2.sc.chinaz.com/Files/pic/pic9/202008/apic27002_s.jpg">
#     </a>
# </div>'''

img_src_list = re.findall(ex, page_text, re.S)  # re.S是为了过滤掉空格和换行
for img_src in img_src_list:
    img_name = img_src.split("/")[-1]
    # 因为没用os,所以文件路径中间需要加/
    img_path = dirName + '/' + img_name
    # 下载图片到本地
    request.urlretrieve(img_src, img_path)
    print(img_name+"下载成功")

下载成功

d273d25e63b63366c779f821e64355bf.png

2.bs4

html相关特性:

  • html和xml的区别:
    • 1.html的标签和属性不可以自定义,而xml就是自定义的标签和属性
    • 2.html使用来展示数据的,而xml是用来存储数据
  • 特性:标签都是成对出现.

html展示的数据都在哪里出现?

  • 直接存储在标签之间
  • 直接存储在标签的属性中

数据解析的通用原理:

  • 1.标签定位
  • 2.指定标签中的数据进行提取

bs4的实现流程:

  • 1.环境安装:pip install bs4,pip install lxml
  • 2.实例化一个BeautifulSoup对象,且将被解析的页面源码数据加载到该对象中
  • 3.调用该对象中的相关方法和属性进行标签定位和数据提取

实例化一个BeautifulSoup对象的方式

  • 针对解析本地存储的html文件 -BeautifulSoup(fp,'lxml')
  • 针对从互联网上请求到的页面源码数据
    • BeautifulSoup(page_text,'lxml')

bs4规则

标签定位
1. soup.tagName,只能定位到第一次出现的该标签,且将定位到的标签以字符串的形式进行了返回
print(soup.div)

2.实现属性定位soup.find('tagName',attrName='value'),find返回的是单数,find_all返回复数(列表)
print(soup.find('div',class_='tang'))
print(soup.find_all('div',class_='song'))

3.选择器定位
print(soup.select('.tang')) #将class为tang的所有标签定位到

层级选择器:大于号表示一个层级,空格表示多个层级
print(soup.select('.tang > ul > li > a'))
print(soup.select('.tang > ul a'))

取文本
a_tag = soup.find('a',id='feng')
print(a_tag.string) #取出标签中直系的文本内容

div_tag = soup.find('div',class_='tang')
print(div_tag.text) #取出标签下所有的文本内容,比如一个div下面的所有p标签里面的内容

取属性
a_tag = soup.find('a',id='feng')
print(a_tag['href']) #取属性

例:三国,爬取静态网页并用bs4解析

https://www.shicimingju.com/

import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}
url = "https://www.shicimingju.com/book/sanguoyanyi.html"
page_text = requests.get(url, headers=headers).text
soup = BeautifulSoup(page_text, "lxml")
# 可以链式操作,但只会有一条数据
# print(soup.find('div', class_="book-mulu").find('ul').find('li').find('a'))
obj_list = soup.select('.book-mulu > ul > li > a')
# print(obj_list)
# [<a href="/book/sanguoyanyi/1.html">第一回·宴桃园豪杰三结义  
# 斩黄巾英雄首立功</a>, <a href="/book/sanguoyanyi/2.html">第二回·张翼德怒鞭督邮
# 何国舅谋诛宦竖</a>

fp = open("./sanguo.txt", "w", encoding='utf-8')

for obj in obj_list:
    title = obj.string
    # print(obj['href'])  # /book/sanguoyanyi/1.html ......
    # 构造url,response,soup
    detail_url = 'https://www.shicimingju.com%s' % obj.get("href")
    detail_text = requests.get(detail_url, headers=headers).text
    # 解析txt
    detail_soup = BeautifulSoup(detail_text, "lxml")
    detail_content = detail_soup.find('div', class_='chapter_content').text
    # 写进文件中
    fp.write(title + 'n' + detail_content + 'n')
    print(title + '爬取成功')
fp.close()

1bfef6591736c62a427ee680586aa1b0.png

3.xpath(最为通用)

  • 解析的流程
    • 1.实例化一个etree对象,且将被解析的数据加载到该对象中
    • 2.调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
  • etree对象的实例化
    • 针对本地文件:etree.parse(filePath)
    • 针对互联网:etree.HTML(page_text)
  • xpath的独特的使用方式
    • 可以增加xpath的通用性 有名用户://div/a/p/span/text() 匿名用户://a/div/p/text() 综合形式://div/a/p/span/text() | //a/div/p/text()
  • pyquery(自学)

xpath表达式规则:

#标签定位的xpath表达式

#1.定位title标签
#最左侧的/:一定要从根节点开始进行标签定位
#非最最测的/:表示一个层级
#最左侧的//:可以从任意位置进行节点定位
#非最左侧的//:表示多个层级
print(tree.xpath('/html/head/title')[0])
print(tree.xpath('/html//title')[0])
print(tree.xpath('//title')[0])

#2.属性定位&索引定位(索引从1开始)
print(tree.xpath('//a[@id="feng"]'))
print(tree.xpath('//div[@class="tang"]/ul/li[1]'))

#数据的提取
print(tree.xpath('//div[@class="song"]/p[3]/text()')[0]) #取直系的文本内容
print(tree.xpath('//div[2]//text()'))

print(tree.xpath('//a[@id="feng"]/@href')) #取属性

数据练习

import requests
from lxml import etree

# 加载本地文件
tree = etree.parse('./test.html')
# 寻找标签
# print(tree.xpath('/html/body/div[@class="song"]/a/@title'))
print(tree.xpath('/html/body/div[@class="song"]/a')[0])
# <Element a at 0x1d6690a12c8>
print(tree.xpath('/html/body/div[@class="song"]/a'))
# [<Element a at 0x1d6690a1248>, <Element a at 0x1d6690a1308>]
print(tree.xpath('/html/body/div[@class="song"]/a/text()'))
# ['nttt', 'ntt宋朝是最强大的王朝,不是军队的强大,而是经济很强大
# ,国民都很有钱', '总为浮云能蔽日,长安不见使人愁']
print(tree.xpath('/html/body/div[@class="song"]/a/text()')[2])
# 总为浮云能蔽日,长安不见使人愁

ab507999623feb20463be7912ea5900a.png

如何在网页中获取xpath路径

b2e2dc52b3d974acfd86c5cfbcd2669b.png

复制的结果为

/html/body/div[2]/a[1]

例:利用xpath爬取美女图片并保存在本地

http://pic.netbian.com/4kmeinv

查看网页的代码,打开抓包工具,点击console,输入document.charset就会显示编码
>> document.charset
>> "GBK"

爬图片代码

import requests
from lxml import etree
import os

# 创建本地存储文件夹
dirName = "Girllibs"
if not os.path.exists(dirName):
    os.mkdir(dirName)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}
# 爬取十页的内容,因为第一页和其他页码的url不一样,所以重新构造一下
for index in range(1, 11):
    if index == 1:
        url = "http://pic.netbian.com/4kmeinv/"
    else:
        url = "http://pic.netbian.com/4kmeinv/index_%d.html" % index

    response = requests.get(url, headers=headers)
    response.encoding = 'gbk'
    page_text = response.text

    # 数据解析
    tree = etree.HTML(page_text)
    # print(tree)
    # 现在里面没有text,只有属性,所以只能用@class来取到值
    image_list = tree.xpath('//div[@class="slist"]/ul/li/a/img')
    # 遍历Image_list然后保存到本地
    for img in image_list:
        # print(img.xpath('./@src'), img.xpath('./@alt'))
        # ['/uploads/allimg/170705/232057-1499268057f947.jpg']['刘奕宁Lynn 白色衣服 黑色短裙 长发清新美女4K壁纸']
        # 局部的数据解析:在上述操作定位到的标签表示的局部数据中进行数据解析
        # 在局部数据解析中./表示的就是xpath的调用者对应的标签
        # 构造图片名称和路径
        img_name = img.xpath('./@alt')[0] + '.jpg'
        img_path = dirName + '/' + img_name

        # 爬取图片
        img_url = "http://pic.netbian.com" + img.xpath('./@src')[0]
        # content返回的是二进制内容
        img_data = requests.get(img_url, headers=headers).content

        # 保存图片到本地
        with open(img_path, 'wb') as fp:
            fp.write(img_data)
            print(img.xpath('./@alt')[0] + '下载完了')

例:爬取糗事百科

https://www.qiushibaike.com/text/

import requests
from lxml import etree
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
for index in range(1, 15):
    url = 'https://www.qiushibaike.com/text/page/%d/' % index
    response = requests.get(url, headers=headers).text
    tree = etree.HTML(response)
    # 查找标签的时候,有些标签的里面的a标签有两个,所以需要加下标
    res_list = tree.xpath('//div[@class="article block untagged mb15 typs_long"]/a[1]')
    # print(len(res_list))
    for res in res_list:
        # print(res.xpath('./@href')[0])  # 格式为:/article/123589129
        detail_url = 'https://www.qiushibaike.com' + res.xpath('./@href')[0]
        # print(detail_url)
        detail_response = requests.get(detail_url, headers=headers).text
        detail_tree = etree.HTML(detail_response)
        title_list = detail_tree.xpath('//div[2]/div/div[2]/div[2]/div[1]/div')[0]
        # for title_index in title_list:
        title = title_list.xpath('./text()')
        print(title)

例:语音合成功能(百度ai)

https://ai.baidu.com/

先安装模块

pip install baidu-aip

代码:

from aip import AipSpeech

""" 你的 APPID AK SK """
APP_ID = '17272609'
API_KEY = 'h3Grp2xXGG0VeSAKlDL9gc4Q'
SECRET_KEY = 'WEEeDpICnzifwBAGF4QW4QiGgSb1u3ND'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
text = '闺蜜比较汉子,我教她,要做一个瓶盖拧不开淑女才有人疼,她表示接受。她拿着一罐八宝粥弱弱的走到心仪男神面前:李哥,帮我拆一下好么,我怕撕不好会伤到手的。李哥和煦一笑,接过撕开瓶口,温柔的递给闺蜜,闺蜜看李哥的表现非常开心,很自然的一把薅过八宝粥,仰头一口闷,喝完大手抹了下嘴巴,嚎了一句:真特么太好喝啦'
result  = client.synthesis(text, 'zh', 1, {
    'vol': 5,
    'per':4
})

# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
    with open('audio.mp3', 'wb') as f:
        f.write(result)

小总结

  • 反爬机制:
    • UA检测,robots,图片懒加载
  • 参数动态化
    • get:params
    • post:data/json
  • headers字典:定义相关的请求头
  • 动态加载数据
    • 生成方式:ajax,js
    • 检测方式:基于抓包工具进行一个局部搜索
    • 如何捕获:基于抓包工具进行全局搜索
    • 如果基于抓包工具进行全局搜索,搜索不到?说明什么?
      • 请求到的数据是经过加密 request高级
  • cookie
  • 代理
  • 模拟登陆
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值