当前位置: 首页 > news >正文

菏泽做网站网站开发项目的里程碑

菏泽做网站,网站开发项目的里程碑,一个空间可以做几个网站,红包打赏的网站怎么做爬虫是一种模拟浏览器实现#xff0c;用以抓取网站信息的程序或者脚本。常见的爬虫有三大类#xff1a; 通用式爬虫#xff1a;通用式爬虫用以爬取一整个网页的信息。 聚焦式爬虫#xff1a;聚焦式爬虫可以在通用式爬虫爬取到的一整个网页的信息基础上只选取一部分所需的…爬虫是一种模拟浏览器实现用以抓取网站信息的程序或者脚本。常见的爬虫有三大类 通用式爬虫通用式爬虫用以爬取一整个网页的信息。 聚焦式爬虫聚焦式爬虫可以在通用式爬虫爬取到的一整个网页的信息基础上只选取一部分所需的信息。 增量式爬虫增量式爬虫每次只爬取网站中更新的信息。 传输协议 我们知道当我们点进某个页面时一般我们的客户端会向服务器发送HTTP请求报文。其中报文里面很重要的一个内容就是报文的头信息包括请求行、首部行等它们包含了我们请求的一些基本信息。所以我们有必要了解如何找到客户端和服务器端的相互传输的HTTP报文的头信息先打开任意一个网址按下键盘的F12 在打开的窗口中点击network栏再在Name一栏随意找到该网页中的某个对象点击后选择右端的headers即可看到我们发送的报文一些头信息。 然而为了防止传输的报文被第三方拦截泄露信息一般情况下我们的传输过程会加上一些保密协议例如HTTPS就比HTTP更加安全因为它采用了证书密钥的加密方式。 requests模块 报文请求过程 因为爬虫是模拟浏览器发送报文所以我们需要先知道怎么模拟浏览器实现向服务器发送请求功能。正好Python中就为我们提供了相应的功能模块--“requests”。 我们需要明确浏览器发送时它共经历了三个步骤1、获取URL点击网址2、向服务器发送请求报文等待加载3、得到、处理响应报文页面展示所以我们需要利用requests模块也需要模拟出上面三个过程。下面以获取百度首页文字为例 1、获取URL 导入该模块并且开辟一个变量来存储目标URL。 import requestsurl https://www.baidu.com 2、发送请求 这里我们模拟的是使用GET方法的报文当然我们也可以模拟使用POST、DELETE等方法的报文。具体发送请求就调用requests模块里面的get方法它常用有三个参数url、params和headers。我们这里先只传入url。因为我们使用的是get方法所以它会返回一个响应报文。 import requestsurl https://www.baidu.com/?tn44004473_52_oem_dg response requests.get(url) 3、处理响应报文 我们将得到的响应报文存到变量response里面并且将其字符编码设置为“utf-8”防止乱码。然后我们的目标是获取返回的报文里面的文字信息所以我们将其文章的文字信息以字符串的形式存储到一个文件里面。 import requestsurl https://www.baidu.com/?tn44004473_52_oem_dg response requests.get(url) response.encoding utf-8 file open(./myget.html, w, encodingutf-8) file.write(response.text) file.close() 这样我们运行生成的html就可以访问到百度的主页文字了 静态网页采集 之前只是获取一个特定的网页的信息下面我们以实现采集利用关键词搜索出来的网页内容为例子看如何获取我们想要的网页搜索 以百度搜索为例我们利用百度搜索某个关键词时使用的URL如下 所以一般搜索类的URL结构如下百度 域名s?wd“我们的问题” 所以我们在爬取网页内容之前需要模仿关键词搜索实现URL中包含我们需要搜索的内容。为了实现在URL中插入参数变量get方法提供了一个params参数我们只需要向其传入一个需要搜索的关键字即可这个关键字一般存储于一个字典中。以百度搜索为例我们的问题对应的键就是’wd‘  import requestsurl https://www.baidu.com/s rec input() dic {wd: rec } response requests.get(url url, params dic) response.encoding utf8 text response.text file open(./output.html, w, encodingutf8) file.write(text) file.close() 但是这还不够我们还需要注意的一点是我们使用这个方法还不能获取当前的网页有一网页服务器发现我们不是浏览器发送的请求会拒绝响应。所以我们需要加上一些伪装信息绕过一些服务器有反爬机制。所以需要利用get方法的第三个常用参数headers头信息假装我们是浏览器发送的报文而非爬虫程序一般加入Cookie和Accept即可了。要想知道自己这些信息打开网页按下F12即可看到 加上我们自己的伪装后的程序可以直接不需要验证就获取网页 import requestsurl https://www.baidu.com/s rec input() dic {wd: rec } headers {Accept: ...User-Agent:...Cookie:... } response requests.get(url url, params dic, headersheaders) response.encoding utf8 text response.text file open(./output.html, w, encodingutf8) file.write(text) file.close()动态网页采集 但是并不是所有访问网页上端显示的URL都能获取到对应的完整界面有时候网页上有一些信息是通过AJAX请求后才返回给我们的下面是判断信息是否为AJAX请求返回的 假如我们打开bilibili找到电影索引的网页我们目标是想获取所有电影的名字和评分并将从第一页到第四页的电影名和对应评分都获取下来存到对应的txt文件中所以需要知道怎么获取其信息。按下F12我们在All里面找到对应该页面的URL的对象但是它的response里面没有找到我们需要的数据那么就证明这些数据不是直接通过访问URL获取的而是由AJAX请求后再传输给我们的。 我们可以再次定位到XHR一栏逐个寻找找到Response里面包含电影名的那个Name查看头信息获取其URL和返回的文件类型json类型以此来模拟浏览器请求过程。 import json import requestsurl https://api.bilibili.com/pgc/season/index/result headers {User-Agent:...} file open(./output.txt, w, encodingutf8) for i in range(1,5):params{st: 2,order: 2,area: -1,style_id: -1,release_date: -1,season_status: -1,sort: 0,page: i,season_type: 2,pagesize: 20,type: 1}response requests.get(urlurl, headersheaders, paramsparams).json()for p in response[data][list]:file.write(电影名p[title] 评分p[score]\n) file.close() 数据解析 上面使用到的requests模块主要还是用于获取一整张网页但是我们很多情况下只需要某部分对应的信息这时候我们就需要对采集的数据进行解析了解析位于标签之间的文本内容或文本属性。 所以总结我们数据解析的步骤可以大致分为两步1、定位到该信息的标签2、从该标签中提取该信息。 针对上面的数据解析我们主要利用bs4和xpath的解析方法。 bs4 bs4的数据解析方法共分为两步 1、将请求到的页面源码赋予给实例化的对象Beautifulsoup 2、调用Beautifulsoup的属性或者方法来从标签中获取我们所需的内容 在我们使用bs4的方法前需要先导两个包bs4包和解释源码用到lxml包 pip install bs4 pip install lxml 第一步实现 然后我们既可以实例化出一个BeautifulSoup对象bs了实例化需要向BeautifulSoup里传入两个参数1、我们获取的网页源码2、固定是lxml的解析方式。其中所需的源码就是我们曾经使用get方法中的text方式获取到的对应网页的数据。 第二步实现 1、定位 再者就是如何调用实例化出来的对象bs里面的方法和属性来获取对应标签里面的所需信息了。常见的使用方法或者属性有bs.find()、bs.find_all、bs.tagname。 bs.tagname是获取bs对象里面标签名为tagname的第一个标签的内容相似地bs.find(tagname)也是找出第一个标签名为tagname的标签里面的内容如果想找到更深入还可以加上属性bs.find(tagname, class_‘属性’)要想找到全部标签名为tagmane的标签内容需要使用find_all传入标签名即可。 而挑选某个符合条件的信息需要使用select方法我们向它传递的参数是一个选择器我们可以选择传递类选择器标志为 . 号、id选择器标志位#号或者标签名选择器等等...或者我们还可以传递层选择器“上一级标签 次级标签 最低级标签”、如果有非隶属则换为空格。 2、获取 当我们利用定位获取到当前信息存储到标签位置时我么们就需要考虑如何去获取这些信息了在BeautifulSoup模块中其为每一个实例出来的对象都提供了两个属性和一个方法来获取这些信息我们以bs.tagname为定位标签则获取信息的方式是bs.tagname.text 、 bs.tagname.get_text() 、 bs.tagname.string。但是这三者中前两者可以获取当前标签下的所有内容而后者只能获取当前标签下的直隶内容。 import json import requests import lxml from bs4 import BeautifulSoupurl https://blog.csdn.net/m0_61151031 headers {cookie:....、user-agent: ... } param {spm: 1011.2415.3001.5343 } response requests.get(urlurl, paramsparam, headers headers) response.encodingutf8bs BeautifulSoup(response.text, lxml) title_save [] URL_save [] for j in bs.find_all(article ,class_blog-list-box):URL_save.append(j.find(a)[href]) for i in bs.find_all(h4):title_save.append(i.text)file open(./output.txt, w, encodingutf-8) print(len(title_save)) print(len(URL_save)) for i in range(0,len(title_save)-1):file.write(title_save[i] : URL_save[i]\n) file.close()Xpath 在我们使用Xpath之前需要先安装Xpath所需的解释器 lxml 包 pip install lxml 安装完后下面我们就可以使用Xpath来捕获网页中某个标签对应的具体信息。整个获取过程总结起来为两步1、定位到具体存储的标签2、获取该标签下的信息。实际使用Xpath来操作这两个步骤的过程如下 1、实例化出一个etree对象并且将网页源码赋予该对象 2、调用etree对象里面的xpath方法利用xpath表达式定位到我们所需的标签捕获其内容信息。 下面是作为例子的html文件我们可以看到信息都是夹杂在一些尖括号括起来的标签里边类似这样XX信息/XX html langen headmeta charsetUTF-8 /title测试bs4/title /head bodydivp百里守约/p/divdiv classsongp李清照/pp王安石/pp苏轼/pp柳宗元/pa hrefhttp://www.song.com/ title赵匡胤 target_selfspanthis is span/span宋朝是最强大的王朝不是军队的强大而是经济很强大国民都很有钱/aa href classdu总为浮云能蔽日,长安不见使人愁/aimg srchttp://www.baidu.com/meinv.jpg alt //divdiv classtangullia hrefhttp://www.baidu.com titleqing清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村/a/lilia hrefhttp://www.163.com titleqin秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山/a/lilia hrefhttp://www.126.com altqi岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君/a/lilia hrefhttp://www.sina.com classdu杜甫/a/lilia hrefhttp://www.dudu.com classdu杜牧/a/lilib杜小月/b/lilii度蜜月/i/lilia hrefhttp://www.haha.com idfeng凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘/a/li/ul/div /body /html第一步实现 要想定位到具体的标签首先我们需要有一个etree对象。调用etree的parse方法将本地的html文件传入该方法中如果是网上的html文件需要调用etree的HTML方法该函数会返回一个已解释了html对象 import requests from lxml import etreerec_etree etree.parse(./test.html) 然后我们就可以 调用该对象的方法xpath来定位标签其中xpath方法有多种使用方式不过具体还是向其传入一个标签位置。 一个标签位置的格式为 / 标签名 / 标签名 / 标签名。由 / 符号表示层级关但是我们还可以利用 // 表示多层级关系/ 标签名 // 标签名省略中间的标签名。如果我们以及获取了定位在中间层级的某个对象那么接下来的位置也可以表示为 ./标签名/标签名这里的 ./ 就表示从当前位置开始和Linux系统中用法类似。如果某一层的下一次标签名都相同那么我们需要在相同的标签后面加上[n]n为数字来表示是哪一个标签。 例如上图中P[1]是李清照、P[2]是王安石...这里要注意下标从1开始。 如果定位时要加上标签的属性我们则需要在标签后面加上[class属性]例如上面的例子要定位到具有属性song的标签地址就需要写为 //div[classsong] 下面以定位信息苏轼的标签p为例可以写出多种定位写法 print(rec_etree.xpath(/html/body/div/p[3])) print(rec_etree.xpath(/html//p[3])) print(rec_etree.xpath(//div/p[3])) print(rec_etree.xpath(//p[3])) 从上到下我们依次来看首先第一个是直接完全每一个层级都标清楚的定位第二个是省略了中间层级的定位第三个是省略局部前面层级的定位第四个是省略全部前面层级的定位。 或者有时候可以直接用右键点击该信息复制... 第二步实现 当我们定位到某个标签后我们得到的还只是给elements对象我们要想获取里面对应的信息最简单的方式就是在标签后再加一层/text()但是这样得出来的还只是一个字典 为此我们还需要获取其首元素信息 print(rec_etree.xpath(/html/body/div/p[3]/text())[0]) print(rec_etree.xpath(/html//p[3]/text())[0]) print(rec_etree.xpath(//div/p[3]/text())[0]) print(rec_etree.xpath(//p[3]/text())[0]) 但是我们仔细看可以看到有时候有些我们需要的信息没有存在标签之间而是存在了标签里边作为标签的属性这时候我们就需要在定位到标签后加上..标签名/属性名来获取这个属性。 print(rec_etree.xpath(//div[classsong]/a[title赵匡胤]/href)[0]) 验证码 验证码是服务器指定的一种反爬机制当我们登录某些网址时在输入了账号和密码后系统可能需要我们输入一个随机的验证码这样可以有效地防止我们的爬虫程序模拟登录因为程序预先不知道系统会给哪些个验证码以此来保障反爬。 为此我们要想爬取需要验证码的网址需要借助一些第三方验证码识别工具进行验证码破解或者人工识别图片或者用专门的AI图片识别算法。 多线程 现在我们需要考虑一种情况如果我们一次性需要请求很多的URL那么系统会如何去执行我们的代码呢下面是一次模拟请求情况的代码 import requestsurl [url1url2url3... ] headers {... }def get_status(each_url):response requests.get(urlurl, headersheaders)return response.status_codefor each_url in url:ret get_status(each_url)print(ret) 我们将输出每一个请求的URL的返回状态码。系统会将我们的URL通过GET函数一次一次地串行发送过去这样也就表面如果GET函数发送请求一个报文并获得响应需要1s那么100个URL请求将要花费100s更多情况下花费地时间将更长 其实我们回过头来看问题主要还是出在了每一次GET只发送一个URL的请求下面为串行通信的示意 为了解决这个问题人们提出的方案为开辟多个进程进行发送也就是使用并行的通信方式这种方式的示意图如下虽然多线程的通信可以大大减少发送的时间但是每次调用就开辟一个进程用完就关掉的往复操作却增大了CPU的工作量所以每一个方法都会有副作用  除了上面的两种方法聪明的人们还想出了另外一种方法线程池它在多线程的基础上进行修改基本原理为一次开辟多个进程然后用这些有限的线程池来进行数据传输这样可以有效地避免了多线程情况下线程使用的开关开关操作导致的消耗。下面我们来做两个例子对比一下 首先是模拟单线程模拟的例子的思路是用一个函数operation这个函数将期待我们发送报文的函数其中每次get函数所导致的阻塞时间就由sleep函数来模拟每次的url就由一个elements列表来表示。 from time import *start time() def operation(element):sleep(2)elements [1, 2, 3, 4] for i in elements:operation(i) end time() print(您一共花费了%lf%(end-start)秒) 通过测试上面的代码我们可以得到共花费的时间 然后我们来使用多线程传输。要想实现多线程传输我们首先需要导入一个包这个包里面的Pool类将帮助我们创建一个多线程对象其中初始化对象时传进去的参数就是未来我们将开辟的线程池的总线程数 from time import * from multiprocessing.dummy import Poolstart time() def operation(element):sleep(2)elements [1, 2, 3, 4] pool Pool(4) pool.map(operation, elements)end time() print(您一共花费了%lf%(end-start)秒) 然后调用实例化出来的多线程对象的map方法向其传入产生通信阻塞的操作这里是operation函数和需要向该操作传递的参数。它就会帮助我们使用多线程的动作来实现这个操作并且如果该操作本身有返回值那么它也会向我们返回某些数值。 所以使用了多线程那么理论上消耗时间将变为原来的1/4 当然如果使用3个线程那么类似木桶理论传输时间取最大的值也就是先用三进程传输3个再用三进程中其中一个传输第四个数所以共消耗4s左右 协程 协程的定义及其实现过程 在我们学习协程之前首先需要理解协程的定义下面的解释来自百度百科 协程不是进程或线程其执行过程更类似于子例程或者说不带返回值的函数调用。 总的来说协程是运行在线程之上的函数调用操作之所以选择这么做是因为有时候即使我们开启了线程池同时阻塞的情况也是可能存在线程之间由于阻塞而等待切换的过程会导致时间以及空间上的浪费。所以发明一种协程可以单独运行在堵塞的线程之上当一个协程完成后另一个可以补上并且它还不会增加线程的数量。 下面我们来看看如何用Python实现协程 协程对象及事件循环 因为协程本质是一个函数调用所以我们首先需要定义一个函数并且为其加上关键字async这就表明这个函数不再是一个简单的函数它会会返回一个协程对象并且当我们再次调用这个函数时函数里面的语句不会被执行 当我们利用async修饰一个函数后调用该函数会返回一个协程对象并且如果我们想去使用这个协程对象需要先创建一个事件循环我们只有将协程对象注册进事件循环里面其才能被执行这个过程就像先烧一锅开水事件循环然后才能放方便面协程对象下去焖执行。而创建一个事件循环就是调用asyncio里面的方法并且还需要启动它和放入协程对象。 import asyncioasync def func1():print(函数已调用)ret func1() loop asyncio.get_event_loop() loop.run_until_complete(ret)基于事件循环创建任务对象 关于函数func1返回的协程对象ret我们还可以将其封装成一个任务对象它在原来协程对象的基础上会增加一些对象的状态而封装的方法就是调用loop里面的方法方法调用完后会返回一个新的任务对象它具有大部分协程对象的性质 import asyncioasync def func1():print(函数已调用)ret func1() loop asyncio.get_event_loop() task loop.create_task(ret) loop.run_until_complete(task) print(task)下面就是task对象所附带的状态信息的输出 基于asyncio创建任务对象 除了上面利用loop创建任务对象的方法我们还可以利用一种别的方式来创建任务对象具体是直接调用asyncio里面的ensure_future方法向其传入协程对象即可创建出一个任务对象 import asyncioasync def func1():print(函数已调用)ret func1() loop asyncio.get_event_loop() task asyncio.ensure_future(ret) loop.run_until_complete(task) print(task) 回调函数 如果我们想在函数执行完后绑定一个回调函数只需要调用下面的方法将task和该回调函数绑定即可这样在事件循环中凡是执行了task任务对象后它会调用这个回调函数 import asyncioasync def func1():print(函数已调用)return adef show_ret(task):print(task.result()) ret func1() loop asyncio.get_event_loop() task loop.create_task(ret) task.add_done_callback(show_ret) loop.run_until_complete(task) 协程的优势测试 下面我们就一个具体的例子来看看协程的优势 下面是一组测试代码具体的意思是我们先创建一个协程对象然后在这个协程对象里面写一个睡眠函数让函数执行停止2秒模仿等待过程注意这里要用asyncio里面的sleep函数因为time包里面的sleep函数是基于同步线程如果堵塞会等待当前任务响应才继续处理下一个任务实现的而我们的多任务协程的实现方式是异步线程如果堵塞将任务挂起直到收到回应才重新处理不阻碍线程这里如果调用基于同步实现的函数会失效。同时注意在前面加上一个await的挂起操作然后使用一个for循环来模仿多任务的情况每一次循环都会创建一个协程对象并且基于其来创建一个任务对象。最后将存储任务的任务列表注册到事件循环中这里注意要调用因为是任务列表所以要使用wait。 import asyncio from time import * start time()async def func():print(调用该函数)await asyncio.sleep(2)task_list[] loop asyncio.get_event_loop() for i in range(0,3):ret func()task loop.create_task(ret)task_list.append(task)loop.run_until_complete(asyncio.wait(task_list)) end time() print(end-start) 协程的具体实现 接下来我们就可以直接来看看如何使用协程进行多任务异步实现我们一次性爬取百度搜索的搜狗、360和猎豹页面。按照上面的使用方法我们先创建一个URL的元组然后定义一个请求该URL内容的函数并且将加上async的定义关键字此时这个函数将会返回一个协程对象。然后创建一个事件循环并且每一次都将协程对象创建出来的任务对象放进事件循环中执行。 import requests import asyncio import time start time.time() urls [https://www.baidu.com/s?wd%E6%90%9C%E7%8B%97,https://www.baidu.com/s?wd360,https://www.baidu.com/s?wd%E7%8C%8E%E8%B1%B9] headers {Accept: ...User-Agent:...Cookie: ... }async def get_content(url):ret requests.get(urlurl, headersheaders)print(success!)loop asyncio.get_event_loop() tasks[] for url in urls:ret_ get_content(url)task loop.create_task(ret_)tasks.append(task) loop.run_until_complete(asyncio.wait(tasks)) end time.time() print(end-start) 虽然这样看起来好像实现了异步多任务处理但是实际上requests里面的get函数是一个基于同步处理的函数也就是说我们根本没有利用协程实现异步多任务的处理为了解决这个问题我们需要利用基于异步而写的请求函数为此我们需要使用到aiohttp模块。我们首先需要获取一个请求对象session这个对象将会帮助我们发送请求报文我们会调用aiohttp里面的CilentSession方法来创建一个对象然后类似于requests一样调用对象里面的get方法来获取响应注意这里获取字符串需要使用到text是一个方法而非属性而且请求函数和获取响应报文内容等操作是都需要进行挂起使用await。 async def get_content(url):ret requests.get(urlurl, headersheaders)print(success!)||V async def get_content(url):async with aiohttp.ClientSession() as session:async with await session.get(urlurl, headersheaders) as response:print(success!)//ret await response.text() 使用协程 不使用协程 我们可以明显看出使用了协程的速度比不使用要快  Selenium 因为Selenium的内容有很多所以我另外写了一篇博客来记录我的Selenium学习过程 代理 代理就是我们在客户端和服务器之间构建一个中间桥梁我们可以通过代理服务器来向目标服务器发送请求。这样可以在我们IP被目标服务器封的时候还能够请求到目标服务器的内容或者可以让我们不想直接使用自己的以IP的身份直接请求某个服务器而隐藏起自己的IP。 其中代理IP有三种类型透明、匿名和高匿。 使用透明的代理IP服务器会知道你在使用代理IP并且也知道你的真实IP 使用匿名的代理IP服务器会知道你在使用代理IP但不知道你的真实IP 使用高匿的代理IP服务器不知道你在使用代理IP更不会知道你的真实IP。 参考资料 什么是协程 - 知乎 Day1 - 1.爬虫简介-爬虫的概念和价值_哔哩哔哩_bilibili
http://www.ihoyoo.com/news/21316.html

相关文章:

  • 怎样在绍兴e网做网站三网合一网站模板
  • 建网站 技术重庆传媒公司前十名
  • 南京h5网站开发网站规划建设与管理维护第二版答案
  • 个人网站的建设目标网站推广seo软件
  • 网站的优化与推广分析微信 网站
  • 刷赞网站怎么做网站建设定金做什么会计分录
  • 网站开发 cms天津网站建设平台
  • 给你网站你会怎么做的哈尔滨网站建设2017
  • 网站代发怎么做小学电教检查网站建设资料
  • 做海报的素材那个网站比较好seo怎么刷关键词排名
  • 怎样做网站的当前位置栏自己能做企业网站吗
  • 孝感网站建设软件电子项目外包网站
  • 石岩企业网站建设成都百度推广优化创意
  • 郑州个人网站开发网站建设栏目怎么介绍
  • 微信平台与微网站开发上海网用软件有限公司
  • 网站建设有哪三部淄博做网站多少钱
  • 网站开发 知乎如何设立官方网站
  • 建设部门网站查询建设网站的工作总结
  • 文化传媒建设网站濮阳网络
  • 视频网站开发需求分析网站备案取名
  • 腾讯云如何建设网站软件商店安装下载oppo
  • 网站asp源码做网站如何选择颜色
  • 做餐饮要看的网站专业网站建设专业网站设计
  • 怎么快速做网站排名关键词排名工具
  • 做视频包的网站有哪些石家庄网站建设策略
  • seo网站优化推广费用wordpress音乐站源码
  • 普通网站和营销网站有何不同企业网站改造优化
  • 公司网站域名申请不同网站模块分析
  • 网站里面如何在新闻列表上显示hot怎么在建设银行网站留言
  • 昆山网站建设兼职app宣传推广方案