python爬虫

  • python爬虫

    • 爬虫分类

      • 通用爬虫

        • 通用网络爬虫 是搜索|擎抓取系统(BaiduGoole Yaho等)的重要组成部分,主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份

        • 通用搜索引擎(Search Engine)工作原理

          • 通用网络爬虫 从互联网中搜集网页,采集信息,这些网页信息用于为搜索引擎建立索引以而提供支持,它决定着整个引擎系统的内容是否丰富,信息是否即 时,因此其性能的优劣直接影响着搜索引擎的效果。

        • 步骤

          • 第一步抓取网页

            • 搜索引擎网络爬虫的基本工作流程如下:

              • 1.首先选取一部分的种子URL,将这些URL放入待抓取URL队列; 2.取出待抓取URL,解析DNS得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中,并且将这些URL放进已抓取URL队列, 3.分析已抓取URL队列中的URL,分析其中的其他URL,并且将URL放入待抓职URL队列,从而进入下一个循环...

            • 搜索引擎如何获取一个新网站的URL:

              • 1.新网站向搜索引警主动提交网址: (如百度http://zhanzhang.baidu.com/linksubmit/ur 2.在其他网站上设置新网站外(尽可能处于搜索引擎爬虫爬取范围) 3.搜索引擎和DNS解析服务商(如DNSPod等)合作,新网站域名将被迅速抓取. 但是搜索引擎螂蛛的爬行是被输入了一定的规则则的,它需要遭从一些命令或文件的内容,如标注为nofollow的链接,或者是Robots协议。

          • 第二步数据存储

            • 搜索引擎通过爬虫爬取到的网页,将数据存入原始页面数据库,其中的页面数据与用户浏览器得到的HTML是完全一样的, 搜索引擎蜘妹在抓取页面时,也做一定的重复内容检测,一旦遇到访问权重很低的网站上有大量抄燕、采集或者复制的内容,很可能就不再爬行.

          • 第三步数据预处理

            • 搜索引擎将爬虫抓取回来的页面,进行各种步骤的预处理。 提取文字 中文分词 消除噪音(比如版权声明文字、导航条、广告等……) 索引处理 链接关系计算 特殊文件处理 除了HTML文件外,搜索引擎通常还能抓取和索引以文字为基础的多种文件类型,如 PDF、Word、WPS、XLS、PPT、TXT 文件等。我们在搜索结果中也经常会看到这些文件类型。 但搜索引擎还不能处理图片、视频、Flash 这类非文字内容,也不能执行脚本和程序。

          • 第四步提供检索服务,网站排名

            • 搜索引擎在对信息进行组织和处理后,为用户提供关键字检索服务,将用户检索相关的信息展示给用户。 同时会根据页面的PageRank值(链接的访问量排名)来进行网站排名,这样Rank值高的网站在搜索结果中会排名较前,当然也可以直接使用 Money 购买搜索引擎网站排名,简单粗暴。

      • 聚焦爬虫

        • http协议

          • 介绍

            • HTTP协议 (HyperText Transfer Protocol,超文本传输协议): 是一种发布和接收 HTML页面的方法.

          • 工作原理

            • 网络爬虫抓取过程可以理解为模拟浏览器操作的过程 浏览器的主要功能是向服务器发出请求,在浏览器窗口中展示您选择的网络资源,HTTP是一套计算机通过网络进行通信的规则。

          • HTTP的请求与响应

            • HTTP通信由两部分组成: 客户端请求消息 与 服务器响应消息

        • 统一资源定位符

          • 是用于完整地描述Internet上网页和其他资源的地址的一种标识方法

          • 基本格式: scheme://host[:port#]/path/.../[?query-string][#anchor] scheme: 协议(例如: http, https, ftp) host: 服务器的IP地址或者域名 port#: 服务器的端口 (如果是走协议默认端口,缺省端口80) path: 访问资源的路径 query-string: 参数,发送给http服务器的数据 anchor: 错(跳转到网页的指定锚点位置)

      • 常见状态码

        • 100~139 : 表示服务器成功接收部分请求,要求客户端继续提交其余请求才能完成整个处理过程。 280~299 : 表示服务器成功接收请求并已完成整个处理过程。常用200 (OK 请求成功) 380~399 : 为完成请求,客户需进一步细化请求。例如: 请求的资源已经移动一个新地址、常用302(所请求的页面已经临时转移至新的url) 、307和304 (使用缓存资源)。400~499 : 客户端的请求有错误,常用404 (服务器无法找到被请求的页面) 、403 (服务器拒绝访问,权限不够)。 500~599 : 服务器端出现错误,常用500 (请求未完成。服务器遇到不可预知的情况)。

      • requests模块

        • requests 的底层实现其实就是 urllib3

          • # 查看响应内容,response.text 返回的是Unicode格式的数据 print response.text # 查看响应内容,response.content返回的字节流数据print respones.content # 查看完整url地址print response.url # 查看响应头部字符编码 print response.encoding # 查看响应码 print response.status code

          • 子主题 2

          • import requests # 通过requests模拟发送网络请求 #第一种写法 response=requests.get("http://www.baidu.com") #第二种写法 response=requests.request("http://www.baidu.com") 该方法的结果为Response对象,包含服务器的响应信息

          • 子主题 4

        • get请求

          • 发送不带参数的get请求

            • import requests url = 'https://www.baidu.com' resp = requests.get(url) #获取响应的编码格式 resp.encoding='utf-8' #获取请求后的cookie信息 cookie = resp.cookies headers = resp.headers print('响应状态码:',resp.status_code) print('请求后的cookie信息',cookie) print('获取请求后的网址:',resp.url) print('响应头:',headers) print('响应内容:',resp.text)

          • 带参数的get请求

            • params参数

              • import requests kw={'wd':'python'} r=requests.get("http://www.baidu.com/s?",params=kw) #手动设置编码格式 没有这个获取的是乱码,因为网页编码格式和requests的编码格式不一样 r.encoding='utf-8' print(r.text)

              • import requests url = 'http://www.so.com/s?' params = { 'q':'python' } resp = requests.get(url,params=params) resp.encoding = 'utf-8' print(resp.text)

        • 获取json数据

          • import requests url = 'https://image.baidu.com/user/logininfo?src=pc&page=searchresult&time=1697630091265' resp = requests.get(url) json_data = resp.json() print(json_data) 没有运行出来

        • 获取二进制数据

          • import requests url = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png'#百度首页logo resp = requests.get(url) #存储 with open('logo.png','wb') as file: file.write(resp.content)

        • headers参数

          • #构造请求头信息 headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} r=requests.get('http://www.baidu.com',headers=headers) print (r.request.headers)

        • post请求

          • import requests data = { 'wd': 'python' } url = "http://httpbin.org/post" r=requests.post(url,data=data) r.encoding = "utf-8" print(r.text)

        • 页面解析和数据提取

          • 一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据 和 结构化的数据 非结构化数据:先有数据,再有结构 结构化数据:先有结构、再有数据 。不同类型的数据,我们需要采用不同的方式来处理

            • 非结构化的数据处理 文本、电话号码、邮箱地址 。正则表达式 HTML 文件 。正则表达式 XPath 。CSS选择器

            • 结构化数据处理 json

          • import requests # # 构建参数的字典 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36" } # 通过requests模拟发送网络请求 r = requests.get("https://api.m.jd.com/?appid=item-v3&functionId=pc_club_productPageComments&client=pc&clientVersion=1.0.0&t=1697369934788&loginType=3&uuid=122270672.16972921620572007025571.1697292162.1697292162.1697369707.2&productId=10056643794287&score=0&sortType=5&page=1&pageSize=10&isShadowSku=0&rid=0&fold=1&bbtf=&shield=", headers=headers) r.encoding = 'utf-8' print(r.text)

      • xpath路径表达式

        • xml文档(可扩展标记语言),设计的宗旨是传输数据,类似html标签 xml标签需要我们自行定义 xml被设计为具有自我描述性

          • xml节点关系

            • 父parent

              • 每个元素以及属性都有一个父 book 元素是 title、author、year 以及 price 元素的父:

                • <?xml version="1.” encoding="utf-8"?> <book> <title>Harry potter/title> <author>] K. Rowling</author> <year>2005</year> <price>29.99</price> </book>

            • 子children

              • 元素节点可有零个、一个或多个子在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子

            • 同胞sibling

              • 拥有相同的父的节点 在下面的例子中,title、author、year 以及 price 元素都是同胞

            • 先辈ancester

              • 某节点的父、父的父,等等。 在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素

            • 后代 Descendant

              • 某个节点的子,子的子,等等。 在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素

        • XPath(XML Path Language) 全称: XML Path Language是一种小型的查询语言是一门在XML文档中查找信息的语言,可用来在XML 文档中对元素和属性进行遍历。可在XML中查找信息,支持HTML的查找,依赖lxml库

          • XPath 开发工具 1.开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用) 2.Chrome插件 XPath Helper 3.Firefox插件 XPath Checker

          • nodename选取此节点的所有子节点 /从根节点选取。 //从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 .选取当前节点 ..选取当前节点的父节点 /@xxx提取当前路径下的属性标签。 /text()选取当前路径的文本内容

          • bookstore选取 bookstore 元素的所有子节点 /bookstore选取根元素 bookstore。注释: 假如路径起始于正斜杠(/),则此路径始表到某元素的绝对路径! bookstore/book选取属于 bookstore 的子元素的所有 book 元素 //book选取所有 book 子元素,而不管它们在文档中的位置 bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于bookstore 之下的什么位置。 //@lang选取名为 lang 的所有属性

        • lxml库

          • lxml 是一个HTML/XML的解析器,主要的功能是如何解析和提取 HTML/XML 数据

          • from lxml import etree text = ''' <a id="aging-total-page" role="pagedescription" aria-label="欢迎进入 百度一下,你就知道,盲人用户进入读屏幕模式请按快捷键Ctrl加Alt加R;阅读详细操作说明请按快捷键Ctrl加Alt加问号键。" tabindex="0" href="javascript:void(0)"></a> ''' html = etree.HTML(text) result = html.xpath('/html') re = html.xpath('//a[@id="aging-total-page"]') print(html) print(etree.tostring(html)) print(result) print(re)

        • 爬取起点小说网文本的两种方式

          • import requests from lxml import etree url = 'https://www.qidian.com/rank/yuepiao/' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } # 发送请求 resp = requests.get(url, headers=headers) resp.encoding = resp.apparent_encoding # 解析网页内容 e = etree.HTML(resp.text) names = e.xpath("//div[@class='book-mid-info']/h2/a/text()") authors = e.xpath("//p[@class='author']/a[1]/text()") # 打印结果 for name, author in zip(names, authors): print(name, ":", author)

          • import requests from bs4 import BeautifulSoup url = 'https://www.qidian.com/rank/yuepiao/' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } # 发送请求 resp = requests.get(url, headers=headers) resp.encoding = resp.apparent_encoding # 使用BeautifulSoup解析网页内容 soup = BeautifulSoup(resp.text, 'html.parser') # 获取小说名和作者 novel_list = soup.find_all('div', class_='book-mid-info') for novel in novel_list: name = novel.h2.a.text author = novel.find('p', class_='author').a.text print(name, ":", author)

      • pyquery解析数据

        • pyquery是jQuery的python实现,能够以jQuery的语法来操作解析HTML文档,易用性和捷信速度都很好 非python标准模块,需要安装pip install puquery 测试方式 import pyquery

          • #代表id属性

        • doc = PyQuery(html) #获取节点 print(doc("#main")) #获取父节点、子节点、兄弟节点 print('-----父节点-----') print(doc("#main").parent()) print('-----子节点-----') print(doc("#main").children()) print('-----兄弟节点-----') print(doc("#main").siblings()) print('-----获取属性-----') print(doc("a").attr('href')) print('-----获取标签的内容-----') print(doc("#main").html()) print(doc("#main").text())

        • pyquery的初始方式

          • 字符串方式 from pyquery import PyQuery as pq doc=pq(str) print(doc,type(doc))

            • from pyquery import PyQuery as py html = ''' <html> <head> <title>PyQuery</title> </head> <body> <h1>PyQuery</h1> </body> </html> ''' doc = py(html)#创建 PyQuery 的对象,实际上就是在进行一个类型转换,将str类型转成 PyQuery 类型 print(doc,type(doc)) print(type(html))

          • url方式 from pyquery import PyQuery as pq doc =pq(url="http://www.baidu.com",encoding="utf-8") print(type(doc)) print(doc('title'))

            • from pyquery import PyQuery doc = PyQuery(url='http://www.baidu.com',encoding='utf-8') print(doc('title'))

          • 文件 from pyquery import PyQuery as pq doc=pq(filename='demo.html') print(type(doc))

            • from pyquery import PyQuery doc =PyQuery(filename='demo.html') print(doc) print(doc('h1'))

        • 爬取起点小说网

          • import requests from pyquery import PyQuery url = 'https://www.qidian.com/rank/yuepiao' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } resp = requests.get(url,headers=headers) # print(resp.text) #使用字符串初始化方式,初始化PyQuery对象 doc = PyQuery(resp.text) # a_tag = doc('h2 a') # print(a_tag) names = [a.text for a in doc('h2 a')] # print(names) # print('------') authors = doc('p.author a.name') # print(authors) author_list =[] for au in authors: text = PyQuery(au).text() author_list.append(text) # print(text) # print(author_list) # print(names) for name,author in zip(names,author_list): print(name,':',author)

      • BeautifulSoup

        • 是一个可以从HTML或XML文件中提取数据的Python库。其功能简单而强大、容错能力高、文档相对完善,清晰易懂非Python标准模块,需要安装才能使用pip install bs4 测试方式 import bs4

          • 子主题 1

          • 子主题 2

        • bs = BeautifulSoup(html,"lxml")

          • from bs4 import BeautifulSoup html =''' <html> <head> <title>ck</title> </head> <body> <h1 class= 'info bg' float ='left'>huanying</h1> <a href='https://www.mashibing.com'>马士兵</a> <h2><!--->注释</h2> </body> </html> ''' bs = BeautifulSoup(html,"lxml") print(bs.title)#获取标签 print(bs.h1.attrs)#获取h1标签的属性 #获取单个属性 print(bs.h1.get("class")) print(bs.h1['class']) print(bs.a['href']) #获取文本内容 print(bs.title.text) print(bs.title.string) #获取内容 print(bs.h2.text)#因为h2中没有正儿八经的文本内容 print('-------',bs.h2.string)#获取h2标签中的文本内容

          • from bs4 import BeautifulSoup html =''' <head> <title>ck</title> </head> <body> <div class= 'info bg' float ='left'>马士兵</div> <div class= 'info bg' float ='left' id='gb'> <span>好好学习,天天上线</span> <a href='https://www.mashibing.com'>官网</a> </div> <span>人生苦短</span> ''' bs = BeautifulSoup(html,"lxml") print(bs.title,type(bs.title)) print(bs.find('div',class_='info'),type(bs.find('div',class_='info')))#获取第一个满足条件的标签 print('-----------') print(bs.find_all('div',class_='info'))#得到的是一个标签的列表 for item in bs.find_all('div',class_='info'): print(item,type(item)) print('----') print(bs.find_all('div',attrs={'float':'left'})) print('---css选择器----') print(bs.select('#gb')) print('------') print(bs.select('.info')) print('-----------') print(bs.select('div>span')) print(bs.select('div.info>span')) for item in bs.select('div.info>span'): print(item.text)

        • 爬取淘宝首页数据

          • import requests from bs4 import BeautifulSoup url = 'https://www.taobao.com/' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } resp = requests.get(url,headers) # print(resp.text) bs = BeautifulSoup(resp.text,'lxml') a_list = bs.find_all('a') print(len(a_list)) for a in a_list: url = a.get('href') # print(url) if url == None: continue if url.startswith('http') or url.startswith('https'): print(url) 只获取到16个,视频获取到135个a标签

      • urllib

        • 简介

          • urllib是Python自带的标准库中用于网络请求的库,无需安装直接引用即可 通常用于爬虫开发、API(应用程序编程接口) 数据获取和测试

          • urllib库的4大模块 ·urllib.request :用于打开和读取URL ·urllib.error:包含提出的例外(异常)urllib.request。urllib.parse:用于解析URL ·urllib.robotparser:用于解析robots.txt文件

            • urllib.parse

              • import urllib.parse kw = {'wd':'马士兵'} #编码 result = urllib.parse.urlencode(kw) print(result) #解码 rea = urllib.parse.unquote(result) print(rea)

            • urllib.request

              • 模拟浏览器发起一个HTTP请求,并获取请求响应结果

              • urllib.request.urlopen的语法格式urlopen(url,data=None,[timeout,]*cafile=None, capath=Nonecadefault=False,context=None) 参数说明 url: url参数是str类型的地址,也就是要访问的URL,例如:https://www.baidu.com data:默认值为None,urllib判断参数data是否为none,从而区分请求方式,或参数data为None,则代表请求方式为get,反之请求方式为post,发送Post请求。参数data以字典方式存储数据,并将data由字典类型转换成字节类型才能完成post请求。 urlopen函数返回的结果是一个http.client.HTTPResponse对象

                • import urllib.request url = 'https://www.lingdianshuwu.com/' #发送请求 resp = urllib.request.urlopen(url) html = resp.read().decode('gbk') #decode将byte类型转换成str类型 print(html)

                  • from urllib import request resp = request.urlopen('http://www.baidu.com') print(resp.read())

                • import urllib.request import urllib.parse url = 'https://www.xslou.com/login.php' data = {'username': '18600605736', 'password': '57365736', 'action': 'login'} # 发送请求 data = urllib.parse.urlencode(data).encode('utf-8') resp = urllib.request.urlopen(url, data=data) html = resp.read().decode('gbk') # 解码是gbk print(html)

                  • from urllib import parse data = {'name':'爬虫基础','greet':'hello world','age':100} qs = parse.urlencode(data) print(qs)

                • #对反爬网站可以操作 import urllib.request url = "https://movie.douban.com/" headers = headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } #构建请求Reques对象 req = urllib.request.Request(url,headers=headers) #使用urlopen打开请求 resp = urllib.request.urlopen(req) #从响应结果中读取数据 html = resp.read().decode('utf-8') print(html)

            • urlopen

              • import urllib.request url = 'https://www.baidu.com' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } #构建请求对象 req = urllib.request.Request(url,headers=headers) #获取opener对象 opener = urllib.request.build_opener() resp = opener.open(req) print(resp.read().decode())

              • import urllib.request response = urllib.request.urlopen('https://www.baidu.com') html = response.read().decode('utf-8') print(html)

      • 正则表达式

        • 是一个特殊的字符序列,它能帮助用户便捷的检查一个字符串是否与某种模式匹配 python的正则模块是re,是python的内置模块,不需要安装,导入即可

        • import re s = 'Istudy study Python3.8 everyday' print('------match方法,从起始位置开始匹配---') print(re.match('I',s).group()) print(re.match('\w',s).group()) print(re.match('.',s).group()) print('-----search方法,从任意位置开始匹配,匹配第一个') print(re.search('study',s).group()) print(re.search('s\w',s).group()) print('----findall从任意位置开始匹配,匹配多个---') print(re.findall('y',s))#结果是列表 print(re.findall('Python',s)) print(re.findall('P\w+.\d',s)) print(re.findall('P.+\d',s)) print('----sub方法,替换功能') print(re.sub('study','like',s)) print(re.sub('s\w+','like',s))

        • 下载糗事百科视频

        • 子主题 4

          • 子主题 1

            • 子主题 1

      • json数据存储

        • JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它是基于ECMAScript的一个子集JSON采用完全独立于语言的文本格式JSON在Pvthon中分别由list和dict组成

        • 子主题 1

          • import json s='{"name":"张三"}' #将字符串转为对象 obj = json.loads(s) print(obj,type(obj)) #将对象转为字符串类型 ss = json.dumps(obj,ensure_ascii=False) print(ss,type(ss)) #将对象dict保存到文件中 json.dump(obj,open("movie.txt",'w',encoding='utf-8'),ensure_ascii=False) #将文件中的内容读取到python程序 obj2 = json.load(open("movie.txt",encoding='utf-8')) print(obj2,type(obj2))

        • 京东商城销售

          • import requests def send_request(): url = 'https://api.m.jd.com/?appid=item-v3&functionId=pc_club_productPageComments&client=pc&clientVersion=1.0.0&t=1697853320125&loginType=3&uuid=122270672.1415644787.1697291560.1697620106.1697852522.4&productId=100028986529&score=0&sortType=5&page=1&pageSize=10&isShadowSku=0&rid=0&fold=1&bbtf=&shield=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } resp = requests.get(url,headers=headers) return resp.text def start(): print(send_request()) if __name__=='__main__': start()

      • ip代理

        • 为什么需要ip代理

          • 假如一个网站它会检测某一段时间某个IP的访问次数,如果访问次数过多,它会禁止你的访问。所以你可以设置一些代理服务器来帮助你做工作,每隔一段时间换一个代理。

        • 分类

          • 透明代理

            • 目标网站知道你使用了代理并且知道你的源IP地址,这种代理显然不符合我们这里使用代理的初衷

          • 匿名代理

            • 匿名程序比较低,也就是网站知道你使用了代理,但是并不知道你的源IP地址

          • 高匿代理

            • 这是最保险的方式,目录网站既不知道你使用了代理更不知道你的源IP

        • 代理方式

          • 免费代理

            • https://www.xicidaili.com/nn/

          • 大象代理

            • 收费 http://www.daxiangdaili.com/

          • 快代理

            • 收费 https://www.kuaidaili.com/

        • from urllib.request import build_opener from urllib.request import ProxyHandler proxy = ProxyHandler({'http':'60.2.44.182:30963'}) opener = build_opener(proxy) url = 'https://www.xslou.com/' resp = opener.open(url) print(resp.read().decode('gbk'))

      • cookie

        • 为什么需要使用Cookie

          • 解决http的无状态性

        • 使用步骤

          • 实例化MozillaCookieJar(保存cookie) 创建 handler对象 (cookie的处理器 创建opener对象 打开网页(发送请求获取响应) 保存cookie文件

        • import urllib.request from http import cookiejar filename = 'cookie.txt' #获取cookie def get_cookie(): #实例化MozillaCookieJar(保存cookie) cookie = cookiejar.MozillaCookieJar(filename) #建handler对象(cookie的处理器 handler = urllib.request.HTTPCookieProcessor(cookie) #创建opener对象 opener = urllib.request.build_opener(handler) #请求网址 url = 'https://tieba.baidu.com/index.html?traceid=#' resp = opener.open(url) #存储cookie信息 cookie.save() #读取cookie def use_cookie(): # 实例化MozillaCookieJar(保存cookie) cookie = cookiejar.MozillaCookieJar() #加载cookie文件 cookie.load(filename) print(cookie) if __name__ == '__main__': #get_cookie() use_cookie()

      • 错误解析

        • 分类

          • urllib.error.URLError:用于捕获由urllib.request产生的异常,使用reason属性返回错误原因

            • import urllib.request import urllib.error #url = 'http://www.google.com' #错误网址会抛出异常 url = "http://www.google.cn" try: resp = urllib.request.urlopen(url) except urllib.error.URLError as e: print(e.reason)

          • urllib.error.HTTPError:用于处理HTTP与HTTPS请求的错误,它有三个属性 ·code:请求返回的状态码 reason:返回错误的原因 headers:请求返回的响应头信息

            • import urllib.request import urllib.error url = 'https://www.douban.com/' try: resp = urllib.request.urlopen(url) except urllib.error.HTTPError as e: print('原因:',e.reason) print('响应状态码:',str(e.code) ) print('响应头数据:' ,e.headers)

      • 文件的写入和读取

        • CSV文件

          • CSV是Comma Separated Values 称为逗号分隔值,以一种以.csv结尾的 CSV文件的特点 值没有类型,所有值都是字符串 不能指定字体颜色等样式· 不能指定单元格的宽高· 不能合并单元格没有多个工作表· 不能嵌入图像图表

          • 向CSV文件中写入数据引入csv模块 使用open0函数创建 csv文件 借助csv.write0)函数创建writer对象 调用writer对象的writerow0方法写入一行数据调用writer对象的writerows0方法写入多行数据

            • import csv with open('student.csv',"a+",newline='') as file: #创建一个writer对象 writer = csv.writer(file) #一次写入一行数据 writer.writerow(['麻雀','20']) # 一次写入多行数据 lst =[ ['jack','20'], ['lili','22'] ] writer.writerows(lst)

          • 从CSV文件中读取数据 引入csv模块 使用open0函数打开CSV文件 借助csv.reader0函数创建reader对象 读到的每一行都是一个列表(ist)

            • import csv with open('student.csv',"r",newline='') as file: #创建一个reader对象 reader = csv.reader(file) for row in reader: print(row)

          • 京东商城评论写入

            • import requests import csv import json def send_request(): # 发送请求获取评论数据的函数 url = 'https://api.m.jd.com/?appid=item-v3&functionId=pc_club_productPageComments&client=pc&clientVersion=1.0.0&t=1697853320125&loginType=3&uuid=122270672.1415644787.1697291560.1697620106.1697852522.4&productId=100028986529&score=0&sortType=5&page=1&pageSize=10&isShadowSku=0&rid=0&fold=1&bbtf=&shield=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } resp = requests.get(url, headers=headers) # 发送GET请求获取评论数据 return resp.text def parse(resp): # 解析评论数据的函数 data = [] json_data = json.loads(resp) # 将响应数据转换为JSON格式 comment_list = json_data['comments'] # 获取评论列表 for comment in comment_list: time = comment['creationTime'].split(' ')[0] # 提取评论时间,只保留日期部分 content = comment['content'] # 提取评论内容 data.append([time, content]) # 将评论时间和内容添加到data列表中 print(f"评论时间:{time}") # 打印评论时间 print(f"评论内容:{content}") # 打印评论内容 return data def save_to_csv(data): # 将评论数据保存到CSV文件的函数 with open('student.csv', 'w', newline='', encoding='utf-8') as file: writer = csv.writer(file) writer.writerow(['评论时间', '评论内容']) # 写入CSV文件的表头 writer.writerows(data) # 写入评论数据 def start(): # 主函数,用于执行整个流程 resp = send_request() # 发送请求获取评论数据 data = parse(resp) # 解析评论数据 save_to_csv(data) # 将评论数据保存到CSV文件 if __name__ == '__main__': start()

        • 多线程和进程

          • 程序·Program,是一个指令的集合就是使用编程语言所编写指令集合,用于实现一定的功能

            • 子主题 1

          • 进程 启动后的程序称为进程,系统会有进程分配内存空间一个进程中至少包含一个线程

          • 线程 CPU的调度执行的基本单元一个进程中包含N多个线程进程结束,线程一定结束,线程结束,进程不一定结束同一个进程中的多个线程,共享内存地址

            • 单线程

              • import time def fun1(): for i in range(5): print('--fun1中i的值为:',i) time.sleep(1) def fun2(): for i in range(5): print('===fun2中i的值为:',i) time.sleep(1) def single(): fun1() fun2() if __name__ == '__main__': single()

            • import time import threading def fun1(): for i in range(5): print('--fun1中i的值为: ',i) time.sleep(1) def fun2(): for i in range(5): print('===fun2中i的值为: ',i) time.sleep(1) def single(): fun1() fun2() def mult(): t1 = threading.Thread(target=fun1) t2 = threading.Thread(target=fun2) #启动线程 t1.start() t2.start() if __name__ == '__main__': # single() mult()

            • 多线程

              • 继承方式实现多线程

                • 为什么要使用类的方式创建线程 因为类可以更加方便的管理我们的代码,可以让我们使用面向对象的方式进行编程 实现多线程的方式 继承threading.Thread类 实现run()方法 调用线程Thread类的start0)方法启动线程

              • 多线程访问全局变量的安全性问题

                • 多线程可以提高程序的运行效率,但同时也会有访问全局变量的安性问题

                • import threading import time ticket = 100 # 全局变量,表示有100张票可以出售 def sale_ticket(): for i in range(1000): global ticket # 对全局变量在函数内部修改需要加一个global if ticket > 0: # 如果还有票可以出售 print(threading.current_thread().getName() + '-->正在出售{}张票'.format(ticket)) ticket -= 1 # 出售一张票,更新票数 time.sleep(1) # 等待1秒钟,模拟买票的过程 def start(): for i in range(2): # 创建2个线程 t = threading.Thread(target=sale_ticket) # 创建线程对象并设置target为sale_ticket函数 t.start() # 启动线程 if name == 'main': start() # 调用自定义的start函数,开始售票过程

              • 锁机制解决线程安全问题

                • threading.Lock类 为了解决多线程访问全局变量所造成的安全性问题可以采用锁机制。 访问全局变量无需加锁 修改全局变量时才需要加锁,修改完毕之后释放锁 加锁的操作步骤 ·创建锁对象 threading.Lock0) 加锁.acquire() 释放锁.release(

                  • import threading import time ticket = 100#全局变量 #创建锁对象 lock = threading.Lock() def sale_ticket(): for i in range(1000): lock.acquire()#枷锁 global ticket #对全局变量在函数内部修改需要加一个global if ticket>0: print(threading.current_thread().getName()+'-->正在出售{}张票'.format(ticket)) ticket-=1 time.sleep(1) lock.release()#释放锁 def start(): for i in range(2): t=threading.Thread(target=sale_ticket)#创建线程对象并启动线程 t.start() if __name__ == '__main__': start()#调用自定义的start函数

            • import threading if __namemain print(threading.enumerate())只有一个主线程

              • import threading import time class CodingThread(threading.Thread): def run(self): thread = threading.current_thread() print(thread) print('线程名称:',thread.getName()) thread.setName('我的线程') print('修改之后的线程名称:', thread.getName()) for i in range(5): print('--fun1中i的值为:',i) time.sleep(1) class CodingThread2(threading.Thread): def run(self): thread = threading.current_thread() print(thread) print('线程名称:', thread.getName()) #修改线程名称 thread.setName('我的线程') print('修改之后的线程名称:', thread.getName()) for i in range(5): print('--fun2中i的值为:',i) time.sleep(1) def mult(): t1 = CodingThread() t2 = CodingThread2() t3 = CodingThread2() t1.start() t2.start() t3.start() print(threading.enumerate()) if __name__ == '__main__': mult() 也是继承的代码

          • 生产者和消费者模式

            • 生产者与消费者模式是多线程开发中常见到的一种模式 生产者线程 生产者线程用于“生产”数据 消费者线程 ·消费者线程用于“消费”数据

              • 子主题 1

            • lock的生产者和消费者

              • import threading import random import time g_money=0 lock=threading.Lock()#创建锁对象 class Producer(threading.Thread): def run(self): global g_money for _ in range(10): lock.acquire() money = random.randint(1000,10000) g_money+= money print(threading.current_thread().getName(),'挣了{}钱,当前余额为:{}'.format(money,g_money)) time.sleep(1) lock.release() class Customer(threading.Thread): def run(self): global g_money for _ in range(10): lock.acquire() money = random.randint(1000, 10000) if money<=g_money: g_money-=money print(threading.current_thread().getName(),'花了{}钱,当前余额为:{}'.format(money,g_money)) else: print(threading.current_thread().getName(), '想花{}钱,但是余额不足,当前余额为:{}'.format(money, g_money)) time.sleep(1) lock.release() def start(): for i in range(5): th=Producer(name='生产者{0}'.format(i)) th.start() for i in range(5): cu=Customer(name='-------消费者{}'.format(i)) cu.start() if __name__ == '__main__': start()

            • Condition版的生产者和消费者

              • 子主题 1

              • import threading import random g_money=0 g_time=0 lock=threading.Condition()#创建Condition对象 class Producer(threading.Thread): def run(self): global g_money global g_time for _ in range(10): lock.acquire() money = random.randint(1000,10000) g_money+= money g_time+=1 print(threading.current_thread().getName(),'挣了{}钱,当前余额为:{}'.format(money,g_money)) lock.notify_all() lock.release() class Customer(threading.Thread): def run(self): global g_money for _ in range(10): lock.acquire() money = random.randint(1000, 10000)#消费的金额 while g_money<money: if g_time>=50: lock.release() return print(threading.current_thread().getName(), '想花{}钱,但是余额不足,当前余额为:{}'.format(money, g_money)) lock.wait()#余额不足的情况下需要等待 g_money-=money#开始消费 print(threading.current_thread().getName(), '--------花了{}钱,当前余额为:{}'.format(money, g_money)) lock.release() def start(): for i in range(5): th=Producer(name='生产者{0}'.format(i)) th.start() for i in range(5): cu=Customer(name='-------消费者{}'.format(i)) cu.start() if __name__ == '__main__': start()

            • 多线程GIL锁

              • GIL锁 Pvthon自带的解释器是CPvthon。CPvthon解释器的多线程实际上一个假的多线程 (在多核CPU中,只能利用一核,不能利用多核) 。同一时刻只有一个线程在执行,为了保正同一时刻只有一个线程在执行,在CPvthon解释器中有一个东西叫GIL (GlobalIntepreter Lock),叫全局解释器锁。 ·GIL可以保证全局同一时刻只有一个线程在执行,但是他不能保证执行代码的原子性。

              • 常见的Python解释器 ·1.Jython: 用Java实现的Python解释器。不存在GII锁 ·2.IronPython: 用net实现的Python解释器。不存在GIL锁·3.PyPy: 用Python实现的Python解释器。存在GIL锁 GIL虽然是一个假的多线程。但是在处理一些IO操作 (比如文件读写和网络请求) 还是可以在很多程序上提高效率的。有IO操作上建议使用多线程提高效率。

            • 多线程的lock锁

              • Lock锁 多个线程访问全局变量时数据的安全性

          • Queue线程安全队列

            • ·Python内置的线程安全的模块叫queue ·FIFO (先进先出) 队列Queue ·LIFO (后进先出) LifoQueue

              • 子主题 1

            • Queue是线程安全的队列,在使用时无需加锁,可以在多线程中直接使用。 队列也是实现线程间同步的的方式

              • from queue import Queue import random import time import threading def add_value(q): while True: q.put(random.randint(100,1000)) time.sleep(1) def get_value(q): while True: print('取出了元素:{0}'.format(q.get())) def start(): q=Queue(10) t1=threading.Thread(target=add_value,args=(q,)) t2= threading.Thread(target=get_value, args=(q,)) t1.start() t2.start() if __name__ == '__main__': start()

            • Queue多线程爬取王者荣耀壁纸

              • 真实数据源

                • 子主题 1

                  • 子主题 1

              • 判断数据来源于服务器还是客户端

                • 点击页面数字底部的分页(下一页)地址栏没有发生变化

                • 从源代码里面搜索p_newhero_item是注释

              • 解决异常

                • 子主题 1

              • 分析url

                • from urllib import parse result=parse.unquote("https%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735062709%2F1687830647%5F1265602313%5F32597%5FsProdImgNo%5F7%2Ejpg%2F200") print(result) https://shp.qpic.cn/ishow/2735062709/1687830647_1265602313_32597_sProdImgNo_7.jpg/200 后面的200换为0

              • 爬取王者第一页壁纸

                • import requests # 导入requests库用于发送HTTP请求 from urllib import parse # 导入parse模块用于URL解析 # 设置请求头,模拟浏览器发送请求 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0", "Referer": "https://pvp.qq.com/" } # 解析壁纸链接 def exact_url(data): img_url_list = [] for i in range(1, 9): # 获取壁纸链接并替换尺寸 img_url = parse.unquote(data.get('sProdImgNo_{}'.format(i), '')).replace('200', '0') if img_url: img_url_list.append(img_url) return img_url_list # 发送请求获取数据 def send_request(): url = "https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=1&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1699449347727" resp = requests.get(url, headers=headers) # 发送GET请求 return resp.json() # 返回JSON格式的响应数据 # 解析JSON数据 def parse_json(json_data):#json_data 是通过 resp.json() 方法从 HTTP 响应中获得的 JSON 数据对象。这个对象通常包含了从服务器返回的结构化数据,可以通过键值对的方式来访问其中的字段和数值。 d = {} # 创建一个空字典用于存储壁纸名称和链接 data_lst = json_data.get('List', []) # 获取JSON数据中的List字段。是在 JSON 数据中获取名为 'List' 的字段。这里使用了 get 方法,它的作用是安全地获取字段的值,如果字段存在则返回其值,如果字段不存在则返回一个默认值,这里的默认值是空列表 [] for data in data_lst: img_url_list = exact_url(data) # 调用exact_url函数解析壁纸链接 sProdName = parse.unquote(data.get('sProdName', '')) # 获取壁纸名称并解码 if sProdName: d[sProdName] = img_url_list # 将壁纸名称和链接存入字典 # 打印解析结果 for item in d: print(item, d[item]) # 主函数 def start(): json_data = send_request() # 发送请求并获取JSON数据 parse_json(json_data) # 解析JSON数据 if __name__ == '__main__': start() # 调用主函数

              • 存储壁纸

                • 路径的拼接 os.mkidr()创建文件夹 request.urlretrieve(url,path)从url处下载文件并存储到path中

                  • import os import requests # 导入requests库用于发送HTTP请求 from urllib import parse # 导入parse模块用于URL解析 from urllib import request # 设置请求头,模拟浏览器发送请求 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0", "Referer": "https://pvp.qq.com/" } # 解析壁纸链接 def exact_url(data): img_url_list = [] for i in range(1, 9): # 获取壁纸链接并替换尺寸 img_url = parse.unquote(data.get('sProdImgNo_{}'.format(i), '')).replace('200', '0') if img_url: img_url_list.append(img_url) return img_url_list # 发送请求获取数据 def send_request(): url = "https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=1&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1699449347727" resp = requests.get(url, headers=headers) # 发送GET请求 return resp.json() # 返回JSON格式的响应数据 # 解析JSON数据 def parse_json(json_data):#json_data 是通过 resp.json() 方法从 HTTP 响应中获得的 JSON 数据对象。这个对象通常包含了从服务器返回的结构化数据,可以通过键值对的方式来访问其中的字段和数值。 d = {} # 创建一个空字典用于存储壁纸名称和链接 data_lst = json_data.get('List', []) # 获取JSON数据中的List字段。是在 JSON 数据中获取名为 'List' 的字段。这里使用了 get 方法,它的作用是安全地获取字段的值,如果字段存在则返回其值,如果字段不存在则返回一个默认值,这里的默认值是空列表 [] for data in data_lst: img_url_list = exact_url(data) # 调用exact_url函数解析壁纸链接 sProdName = parse.unquote(data.get('sProdName', '')) # 获取壁纸名称并解码 if sProdName: d[sProdName] = img_url_list # 将壁纸名称和链接存入字典 # 打印解析结果 # for item in d: # print(item, d[item]) save_jpg(d) def save_jpg(d) : # 遍历字典中的每个键 for key in d : # 拼接路径,将'image'和键连接成一个路径 dirpath = os.path.join('image', key.strip('')) # 检查路径是否存在,如果不存在则创建 if not os.path.exists(dirpath) : os.mkdir(dirpath) # 遍历当前键对应的图片链接列表 for index, image_url in enumerate(d[key]) : # index从0开始 # 下载图片并保存到指定目录中 request.urlretrieve(image_url, os.path.join(dirpath, '{}.jpg').format(index + 1)) # 打印下载完成的提示信息 print("{}下载完毕".format(d[key][index])) # 主函数 def start(): json_data = send_request() # 发送请求并获取JSON数据 parse_json(json_data) # 解析JSON数据 if __name__ == '__main__': start() # 调用主函数

                • 多线程

                  • import os import requests # 导入requests库用于发送HTTP请求 from urllib import parse # 导入parse模块用于URL解析 from urllib import request import threading # 设置请求头,模拟浏览器发送请求 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0", "Referer": "https://pvp.qq.com/" } # 解析壁纸链接 def exact_url(data): img_url_list = [] for i in range(1, 9): # 获取壁纸链接并替换尺寸 img_url = parse.unquote(data.get('sProdImgNo_{}'.format(i), '')).replace('200', '0') if img_url: img_url_list.append(img_url) return img_url_list # 发送请求获取数据 def send_request(): url = "https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=1&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1699449347727" resp = requests.get(url, headers=headers) # 发送GET请求 return resp.json() # 返回JSON格式的响应数据 # 解析JSON数据 def parse_json(json_data):#json_data 是通过 resp.json() 方法从 HTTP 响应中获得的 JSON 数据对象。这个对象通常包含了从服务器返回的结构化数据,可以通过键值对的方式来访问其中的字段和数值。 d = {} # 创建一个空字典用于存储壁纸名称和链接 data_lst = json_data.get('List', []) # 获取JSON数据中的List字段。是在 JSON 数据中获取名为 'List' 的字段。这里使用了 get 方法,它的作用是安全地获取字段的值,如果字段存在则返回其值,如果字段不存在则返回一个默认值,这里的默认值是空列表 [] for data in data_lst: img_url_list = exact_url(data) # 调用exact_url函数解析壁纸链接 sProdName = parse.unquote(data.get('sProdName', '')) # 获取壁纸名称并解码 if sProdName: d[sProdName] = img_url_list # 将壁纸名称和链接存入字典 # 打印解析结果 # for item in d: # print(item, d[item]) save_jpg(d) def download_image(image_url, dirpath, filename): request.urlretrieve(image_url, os.path.join(dirpath, filename)) def save_jpg(d): for key in d: dirpath = os.path.join('image', key) if not os.path.exists(dirpath): os.mkdir(dirpath) for index, image_url in enumerate(d[key]): filename = '{}.jpg'.format(index + 1) # 使用多线程下载图片 t = threading.Thread(target=download_image, args=(image_url, dirpath, filename)) t.start() print("{}下载完毕".format(image_url)) # 主函数 def start(): json_data = send_request() # 发送请求并获取JSON数据 parse_json(json_data) # 解析JSON数据 if __name__ == '__main__': start() # 调用主函数

              • 生产者与消费者多线程

                • import requests from urllib import parse from queue import Queue import threading from urllib import request import os headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0", "Referer": "https://pvp.qq.com/" } def exact_url(data): img_url_list = [] for i in range(1,9): # 获取壁纸链接并替换尺寸 img_url = parse.unquote(data.get('sProdImgNo_{}'.format(i), '')).replace('200', '0') if img_url: img_url_list.append(img_url) return img_url_list #生产者线程 class Producer(threading.Thread): def __init__(self,page_queue,image_url_queue): super(Producer, self).__init__() self.page_queue=page_queue self.image_url_queue=image_url_queue def run(self): while not self.page_queue.empty(): page_url=self.page_queue.get() resp=requests.get(page_url,headers=headers) json_data=resp.json() d = {} # 创建一个空字典用于存储壁纸名称和链接 data_lst = json_data.get('List', []) # 获取JSON数据中的List字段。是在 JSON 数据中获取名为 'List' 的字段。这里使用了 get 方法,它的作用是安全地获取字段的值,如果字段存在则返回其值,如果字段不存在则返回一个默认值,这里的默认值是空列表 [] for data in data_lst : img_url_list = exact_url(data) # 调用exact_url函数解析壁纸链接 sProdName = parse.unquote(data.get('sProdName', '')) # 获取壁纸名称并解码 if sProdName : d[sProdName] = img_url_list # 将壁纸名称和链接存入字典 for key in d : # 拼接路径,将'image'和键连接成一个路径 dirpath = os.path.join('image', key.strip('')) # 检查路径是否存在,如果不存在则创建 if not os.path.exists(dirpath) : os.mkdir(dirpath) # 遍历当前键对应的图片链接列表 for index, image_url in enumerate(d[key]) : # index从0开始 # 生产图片的路径 self.image_url_queue.put({'image_path':os.path.join(dirpath, '{}.jpg').format(index + 1),'image_url':image_url}) #消费者线程 class Customer(threading.Thread): def __init__(self,image_url_queue) : super(Customer, self).__init__() self.image_url_queue = image_url_queue def run(self): while True: try: image_obj=self.image_url_queue.get(timeout=20) request.urlretrieve(image_obj['image_url'],image_obj['image_path']) print(f"{image_obj['image_path']}下载完成") except: break #定义一个启动线程的函数 def start(): page_queue=Queue(1) image_url_queue =Queue(10) for i in range(0,1): page_url=f"https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={i}&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1699449347727" #print(page_url) page_queue.put(page_url) # 创建生产者对象 producer_threads = [] for i in range(5) : t = Producer(page_queue, image_url_queue) t.start() producer_threads.append(t) # 创建消费者对象 consumer_threads = [] for i in range(10) : t = Customer(image_url_queue) t.start() consumer_threads.append(t) # 等待所有生产者线程完成 for t in producer_threads : t.join() # 向image_url_queue添加结束标记,以通知消费者线程结束 for i in range(10) : image_url_queue.put(None) # 等待所有消费者线程完成 for t in consumer_threads : t.join() if __name__ == '__main__': start()

        • Excel文件的读取和写入

          • openpyxl模块简介 ·可以读取和写入Excel文件需要单独安装,不包含有Python标准模块里处理Excel数据 处理Excel公式 处理Excel样式 在表格内插入图表

          • 向Excel文件中写入数据 创建工作薄对象openpyxl.Workbook() 获取活动工作表对象 wbactive 获取单元格sheet[单元格名称] 向单元格中写入数据 cell.value=值 向Excel中写入一行数据sheet.append(列表) 保存Excel文件 wb.save(文件)

            • import openpyxl #创建工作簿对象 wb = openpyxl.Workbook() #获取工作表sheet sheet = wb.active #获取指定的单元格 cell = sheet['A1'] #向单元格中写入数据 cell.value = '中国美丽' #一次写入一行数据 lst = ['姓名','年龄','成绩'] sheet.append(lst) #一次写入多行数据 lst1 =[ ['jack','20',29], ['lili','22',30 ] ] for row in lst1: sheet.append(row) #保存 wb.save('我的Excel文件.xlsx')

          • 从Excel中读取数据 加载工作薄对象openpyxlload_workbook(文件名获取活动工作表对象 wbactive 获取单元格sheet[单元格名称] 获取单元格的值cell.value 获取一系列格子 sheetA],sheet[3],sheet[A:C]获取整个表格的所有行 sheet.rows

            • import openpyxl #加载Excel文件( 创建python中的工作簿对象) wb = openpyxl.load_workbook('我的Excel文件.xlsx') #获取工作表对象 # sheet = wb.active#一个sheet sheet = wb['Sheet']#多个sheet #获取指定的单元格 cell = sheet['A1'] vlaue = cell.value print(vlaue) #获取一系列的格子 columns = sheet['A']#获取整个A列 for col in columns: #获取A列中的每一个单元格 print(col.value)#获取A列中的每一个单元格的值 # print(columns) print('--------') row = sheet[3]#获取第三行 for cell in row:#获取第三行的每一个单元格 print(cell.value)#获取第三行的每一个单元格的值 # print(row) print('-------') cols = sheet['B:C'] print(cols) for col in cols:#获取每一列中的单元格 print(cell.value)

          • 爬取下厨房

            • import requests from bs4 import BeautifulSoup import openpyxl def send_request(): """ 发送请求获取网页内容的函数 """ url = 'http://www.xiachufang.com/explore/' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36' } resp = requests.get(url, headers=headers) # 发送GET请求获取网页内容 return resp.text def parse_html(html): """ 解析网页内容的函数 """ count = 0 # 用于计数菜谱的数量 bs = BeautifulSoup(html, 'lxml') # 使用BeautifulSoup解析网页内容 lst_name = bs.find_all('p', class_='name') # 获取所有菜名元素 lst_category = bs.find_all('p', class_="ing ellipsis") # 获取所有食材元素 lst = [] for i in range(len(lst_name)): count += 1 # 每次循环计数加1 food_url = 'http://www.xiachufang.com' + lst_name[i].find('a')['href'] # 获取菜谱链接 # 将菜谱编号、菜名、食材和链接添加到列表中 lst.append([count, lst_name[i].text[18:-14], lst_category[i].text[1:-1], food_url]) print(lst) save(lst) def save(lst): """ 将数据保存到Excel文件的函数 """ wb = openpyxl.Workbook() # 创建一个新的Excel工作簿 sheet = wb.active # 获取活动的工作表 for row in lst: sheet.append(row) # 将每一行数据添加到工作表中 wb.save('下厨房.xlsx') # 保存Excel文件 def start(): """ 主函数,用于执行整个流程 """ result = send_request() # 发送请求获取网页内容 parse_html(result) # 解析网页内容 if __name__ == '__main__': start()

      • 动态网页爬取

        • 两种方式

          • 动态网页,是在网站不重新加载的情况下,通过ajax技术动态更新网站中的局部数据,比如王者荣耀的高清壁纸,在换页的过程中,url是没有发生改变的。但是壁纸动态的更改了

          • AJAX(Asynchronouse JavaScript AndXML) 异步JavaScrip和XML前端与服务器进行少量数据交换,Ajax可以使用网页实现异更新这意叶着可以在不重新加载整个网页的情况下,部分对网页的某进行更新。传统的网员,如果需要更新内容,必须重载整人网页页面。因为传统的在传输数据格式方向,使用的是XML语法。因此叫AJAX.其实现在数据交互基本上都是使用JSON。使用Aiax加载的数据,即使使用了JS,将数据渲染到了浏览器中,在右键->查看网页源代码还是不能看到通过Aiax加载的数据,只能看到使用这个url加载的html代码

          • 解决方法

            • 直接分析Ajax调用的接口。然后通过代码请求这个接口 使用selenium+chromedirver模拟浏览器行为获取数据

        • selenium

          • 是一个Web自动化测试工具,可以直接运行在浏览器上支持所有主流的浏览器 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,基础页面截图等 非Python标准模块,安装才能使用

            • 安装方式在线安装:pip install selenium

            • 安装浏览器插件 ChromeDriver解压到Python解释器的安装路径

          • 定位元素

            • find_element获取满足条件的第一个元素findelements获取满足条件的所有元素

            • 子主题 2

              • 输入框操作--表单元素1

                • from selenium import webdriver #构造浏览器 driver=webdriver.Firefox() #请求的url driver.get("http://cn.bing.com") #定位元素 #通过id # input_tag=driver.find_element_by_id("sb_form_q") # input_tag.send_keys("python") #通过name属性 # input_tag=driver.find_element_by_name("q") # input_tag.send_keys("python") #通过类样式名称获取 # input_tag=driver.find_element_by_class_name("sb_form_q") # input_tag.send_keys("python") #标签名获取 # input_tag=driver.find_element_by_tag_name("input") # input_tag.send_keys("python") #根据连接文本 # input_tag=driver.find_element_by_link_text("地图") # print(input_tag) #css #input_tag=driver.find_element_by_css_selector("#sb_form_q")#id样式# # input_tag=driver.find_element_by_css_selector('.sb_form_q') # input_tag.send_keys("python") #xpath input_tag=driver.find_element_by_xpath('//input[@class="sb_form_q"]') input_tag.send_keys("python")

                • 操作输入框 通过selenium的定位方式找到元素使用send_keys(value)将值填入

              • 操作复选框和按钮--表单元素2

                • 因为要选中的checkbox(复选)标签,在网页中是通过鼠标点击的。因此想要选中checkbox标签,然后执行click()事件

              • 下拉框select

                • select元素不能直接点击。因为点击后还需要选中元素。Selenium.webdriver.support.ui.Select类专门操作select元素,将获取到的元素当成参数传到这个类中,创建这个类的对象,就可以使用该对象进行选择

                • from selenium import webdriver import time from selenium.webdriver.support.ui import Select #构造浏览器 driver=webdriver.Firefox() #请求的url driver.get("https://kyfw.12306.cn/otn/regist/init") #获取元素 select=Select(driver.find_element_by_id("cardType")) #获取下拉页表框中的项 #(1)根据索引获取 # select.select_by_index(1) #(2)根据value # select.select_by_value('B') #根据可见文本 select.select_by_visible_text('台湾居民来往大陆通行证') time.sleep(5) driver.quit()

            • 使用selenium自动搜索

              • from selenium import webdriver import time #构造浏览器 driver=webdriver.Firefox() #请求的url driver.get("https://www.bing.com/") #获取网页元素 input_tag=driver.find_element_by_id('sb_form_q') input_tag.send_keys("python") #获取按钮 tag=driver.find_element_by_id('sb_form_q') tag.click() print(driver.page_source) time.sleep(5) driver.quit()

          • selenium行为链

            • 为什么需要行为链? 因为有些网站可能会在浏览器端做一些验证行为是否符合人类的行为来做反爬虫。 有更多的复杂操作,在自动化测试中经常使用

            • 行为链如何使用 导入from selenium.webdriver.common.action_chains import ActionChains 创建对象actions=ActionChains(driver) 移动到某元素 actions.move_to_element(element) 文本框填入内容actionssend_keys_to_element(element,python) 单击 actions.click(element)

              • from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains #构造浏览器 driver=webdriver.Firefox() driver.get("https://www.bing.com/") input_tag=driver.find_element_by_id("sb_form_q")#获取到的是文本框 button1=driver.find_element_by_id("sb_form_go")#获取的是提交按钮 #创建行为链(模拟人的行为) actions=ActionChains(driver) actions.move_to_element(input_tag)#移动到文本框上并输入搜索的关键字 actions.send_keys_to_element(input_tag,"Python") actions.move_to_element(button1)#移动到提交按钮 actions.click(button1)#点击提交按钮 #开始执行行为链 actions.perform() 这个没有运行出来

          • selenium操作cookie

            • 获取所有cookie信息driver.get_cookies() 获取指定cookie信息 driver.get_cookie(BAIDUID') 添加cookie driver.add_cookie({'name':'zhangsan','value':"88888"}) 删除cookie driver.delete_cookie('zhangsan') driver.delete_all_cookies()

              • from selenium import webdriver #构造浏览器 driver=webdriver.Firefox() driver.get("https://www.baidu.com/") #获取所有的cookie cookies=driver.get_cookies() for cookie in cookies: print(cookie) #获取指定的cookie信息 cookie=driver.get_cookie("BAIDUID") print(cookie) #添加cookie print("--------") driver.add_cookie({'name':'zhangsan','value':"88888"}) print(driver.get_cookie("zhangsan")) #删除cookie driver.delete_cookie("zhangsan") print(driver.get_cookie("zhangsan")) #删除所有的cookies浏览器的 driver.delete_all_cookies() print(driver.get_cookies())

          • from selenium import webdriver import time #构造浏览器 driver=webdriver.Firefox() #请求的url driver.get("http://www.baidu.com") time.sleep(5) driver.close()#关闭当前页 #截图操作 driver.save_screenshot("baidu.jpg") #获取网页源代码 html=driver.page_source print(html) driver.quit() #关闭浏览器

      • 页面等待

        • 隐式等待

          • 调用 driver.implicitly_wait.那么在获取不可用的元素之前,会先等待N秒钟的时间driver.implicitly_wait()

        • 显示等待

          • 显示等待是表明某个条件成立后才执行获取元素的操作。也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就会抛出一个异常显示等待应用

          • selenium.webdriver.support.excepted_conditions 期望的条件 selenium.webdriver.support.WebDriverWait

        • 12306登陆

          • from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait#显示等待 from selenium.webdriver.support import expected_conditions as ec#等待的条件 driver=webdriver.Firefox()#创建浏览器对象 class TrainSpider(object): login_url="https://kyfw.12306.cn/otn/resources/login.html"#登陆的页面 profile_url="https://kyfw.12306.cn/otn/view/index.html"#个人中心 #定义初始化方法 def __init__(self,from_station,to_station,train_date): self.from_station=from_station self.to_station=to_station self.train_date=train_date #登陆 def login(self): #打开登陆的页面 driver.get(self.login_url) WebDriverWait(driver,1000).until( ec.url_to_be(self.profile_url)#等待到个人中心页面 ) print("登陆成功") #负责调用其他方法,组织其他的代码 def run(self): #登陆 self.login() #启动爬虫 def start(): spider=TrainSpider("长春","北京","2023-11-21") spider.run() if __name__ == '__main__': start()

        • 12306爬取车站代号

          • import requests import re import openpyxl def get_station(): url="https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9278" header={ "User-Agent":"mozilla / 5.0(WindowsNT10.0;Win64;x64;rv: 109.0) Gecko / 20100101Firefox / 119.0" } resp = requests.get(url, headers=header) resp.encoding="utf-8" #print(resp.text) station = re.findall('([\u4E00-\u9FA5]+)\|([A-Z]+)', resp.text) print(station) return station #station是一个列表 def save(lst): wb=openpyxl.Workbook()#创建工作薄对象 ws=wb.active #使用活动表 for item in lst: ws.append(item) #每执行一次append将向sheet中添加一行 wb.save("车站代码.xlsx") if __name__ == '__main__': lst=get_station() save(lst)

        • 12306填充站点代号

          • from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait#显示等待 from selenium.webdriver.support import expected_conditions as ec#等待的条件 import openpyxl driver=webdriver.Firefox()#创建浏览器对象 class TrainSpider(object): login_url="https://kyfw.12306.cn/otn/resources/login.html"#登陆的页面 profile_url="https://kyfw.12306.cn/otn/view/index.html"#个人中心 left_ticket="https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc"#余票查询 #定义初始化方法 def __init__(self,from_station,to_station,train_date): self.fromStationText=from_station self.toStationText=to_station self.train_date=train_date self.station_code=self.init_station_code() #self.station_code结果为字典 #登陆 def login(self): #打开登陆的页面 driver.get(self.login_url) WebDriverWait(driver,1000).until( ec.url_to_be(self.profile_url)#等待到个人中心页面 ) print("登陆成功") #查询余票 def search_ticket(self): #打开查询余票的网站 driver.get(self.left_ticket) #找到出发站的隐藏的html标签 fromStaiton_input=driver.find_element_by_id("fromStationText") toStation_input=driver.find_element_by_id("toStationText") #找到出发时间的input标签 train_date_input=driver.find_element_by_id("train_date") #根据键获取值 from_station_code=self.station_code[self.fromStationText]#根据出发地找到出发地的代号 to_station_code=self.station_code[self.toStationText] #根据目的地找到目的地的代号 #执行js driver.execute_script("arguments[0].value='%s'" % from_station_code,fromStaiton_input) driver.execute_script("arguments[0].value='%s'" % to_station_code, toStation_input) driver.execute_script("arguments[0].value='%s'" % self.train_date, train_date_input) # 负责调用其他方法,组织其他的代码 #负责调用其他方法,组织其他的代码 def run(self): #登陆 self.login() #余票查询 self.search_ticket() def init_station_code(self): wb=openpyxl.load_workbook("车站代码.xlsx") ws=wb.active #使用活动表 lst=[] #存储所有车站名称及代号 for row in ws.rows: #遍历所有行 sub_lst=[] #用于存储每行中的车站名称,车站代号 for cell in row: #遍历一行中的单元格 sub_lst.append(cell.value) lst.append(sub_lst) #print(dict(lst))#将列表转换成字典 return dict(lst) #启动爬虫 def start(): spider=TrainSpider("长春","北京","2023-11-22") spider.run() #spider.init_station_code() if __name__ == '__main__': start()

        • from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ex #构造浏览器 driver=webdriver.Firefox() # driver.get("https://www.baidu.com/") # #隐式等待 # driver.implicitly_wait(5) # driver.find_element_by_id("abc") driver.get("https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc") WebDriverWait(driver,100).until( ex.text_to_be_present_in_element_value((By.ID,"fromStationText"),"长春") ) WebDriverWait(driver,100).until( ex.text_to_be_present_in_element_value((By.ID,"toStationText"),"北京") ) btn=driver.find_element_by_id("query_ticket") btn.click()

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南棋网络安全

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值