sunzhihaofuture 2020-04-10
- 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响应进行搜索
### 今日内容 - 数据解析 - 数据解析的作用 - 可以帮助我们实现聚焦爬虫 - 数据解析的实现方式 - 正则 - 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)
- 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 + "\n") # print(title, "下载成功") # # print("over")
- 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"