推荐文章:搜索引擎如何去抓取网页

优采云 发布时间: 2022-09-23 14:15

  推荐文章:搜索引擎如何去抓取网页

  搜索引擎如何爬网门户网站构建,搜索引擎看似简单的爬-入-仓-查询的工作,但每个环节隐含的算法却非常复杂。搜索引擎依靠蜘蛛来完成爬取页面的工作。爬取动作很容易实现,但是要爬到哪些页面,先爬到哪些页面,需要通过算法来确定。下面介绍几种爬取算法: 1、广度优先爬取策略:我们都知道网站页面大部分都是按照树形图分布的,所以在树形图的链接结构中,页面会先被爬取吗?为什么要优先抓取这些页面?广度优先爬取策略是先按照树形结构爬取同级链接,爬取同级链接后,再爬取下一级链接。如下图所示: 可以发现,我在表达的时候,使用的是链接结构,而不是网站结构。这里的链接结构可以收录任何页面的链接,不一定是网站内部链接。这是一种理想化的广度优先抓取策略。在实际抓取过程中,不可能先想到全宽,而是先限制宽,如下图所示: 上图中,我们的蜘蛛在检索G链接的时候,通过算法发现G页面没有价值,所以悲剧的G链接和低级的H链接被Spider协调。至于为什么G链接是和谐的?好吧,我们来分析一下。2、不完整的遍历链路权重计算:

  

  互联网几乎是无限的,每天都会创建大量新链接。搜索引擎对链接权重的计算只能是不完全遍历。为什么 Google PR 只需要每三个月更新一次?为什么百度一个月更新1-2次?这是因为搜索引擎使用非完全遍历链接权重算法来计算链接权重。其实按照现在的技术,实现更快的频率权重更新并不难,计算速度和存储速度完全可以跟上,但为什么不去做呢?因为没有必要,或者已经实现了,但是我不想发布。那么,什么是非完整遍历链路权重计算呢?我们形成一组K个链接,R代表链接获得的pagerank,S表示链路收录的链路数,Q表示是否参与传递,β表示阻尼因子,则链路得到的权重的计算公式为: 从公式中可以看出,Q决定链接权重。如果发现链接作弊,或者搜索引擎被手动删除,或者其他原因,将Q设置为0,那么再多的外部链接就没用了。β为阻尼因子,其主要作用是防止权重0的发生,使链路无法参与权重传递,防止作弊的发生。阻尼系数β一般为0.85。为什么阻尼因子乘以网站的个数?因为不是一个页面中的所有页面都参与权重传递,搜索引擎将再次删除 15% 的已过滤链接。但是这种不完全的遍历权重计算需要积累一定数量的链接才能重新开始计算,所以一般更新周期比较慢,不能满足用户对即时信息的需求。

  

  因此,在此基础上,出现了实时权重分布抓取策略。即蜘蛛爬完页面并进入后,立即进行权重分配,将权重重新分配给要爬取的链接库,然后蜘蛛根据权重进行爬取。3、社会工程学抓取策略 社会工程学策略是在蜘蛛爬行的过程中加入人工智能或经过人工智能训练的机器智能来确定爬行的优先级。目前我知道的爬取策略有:热点优先策略:爆破热点关键词优先抓取,不需要经过严格的去重和过滤,因为会有新的链接覆盖和用户的主动选择。湾。权限优先策略:搜索引擎会为每个网站分配一个权限度,通过网站历史、网站更新等确定网站的权限度。高度权威的 网站 链接。C。用户点击策略:当在某个行业词库中搜索关键词的次数最多,并且经常点击网站的相同搜索结果时,搜索引擎会更频繁地抓取这个网站。d。历史参考策略:对于不断更新频繁的网站,搜索引擎会为网站建立更新历史,并根据更新历史估计未来更新量,确定爬取频率。SEO工作指导:搜索引擎爬取原理已经深入讲解,所以现在有必要用简单的方式解释这些原则来指导SEO工作。A. 定期、定量的更新,会让蜘蛛准时爬到 网站 页面;B.公司运营网站比个人网站更有权威性;C、网站建站时间长,更容易被爬取;D. 链接在页面中分布要合理,太多或太少都不好;E、受用户欢迎的网站也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 定期和定量的更新会让蜘蛛按时爬到 网站 页面;B.公司运营网站比个人网站更有权威性;C、网站建站时间长,更容易被爬取;D. 链接在页面中分布要合理,太多或太少都不好;E、受用户欢迎的网站也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 定期和定量的更新会让蜘蛛按时爬到 网站 页面;B.公司运营网站比个人网站更有权威性;C、网站建站时间长,更容易被爬取;D. 链接在页面中分布要合理,太多或太少都不好;E、受用户欢迎的网站也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 比个人网站更有权威;C、网站建站时间长,更容易被爬取;D. 链接在页面中分布要合理,太多或太少都不好;E、受用户欢迎的网站也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 比个人网站更有权威;C、网站建站时间长,更容易被爬取;D. 链接在页面中分布要合理,太多或太少都不好;E、受用户欢迎的网站也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 受用户欢迎,也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络 受用户欢迎,也受搜索引擎欢迎;F、重要的页面应该放在较浅的网站结构中;G.网站权威网站内的行业权威信息。这就是本教程的内容。下一篇教程的主题是:页面价值和网站权重的计算。文章来自:作者:矩阵网络

  技术文章:使用Python抓取动态网站数据

  青山大哥探出头来看我苦茶园的信

  这里会用一个例子来讨论多线程在爬虫中的应用,所以就不过多解释理论的东西了,点击连接了解并发详情

  爬取应用商店

  当然,在爬取之前,请自诊断是否遵循君子协议,否则将无法爬取数据

  查看robots协议只需要在域名后缀加上rebots.txt

  例子:

  1. 目标2. 分析2.1 网页属性

  首先需要判断是否是动态加载的

  点击翻页,发现URL后面加了#page=1,表示查询参数为1时为第二页,写一个小爬虫测试一下

  import requests<br /><br />url = "http://app.mi.com/category/15"headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"}<br /><br />html = requests.get(url=url, headers=headers).content.decode("utf-8")<br /><br />print(html)

  在输出的html中搜索“王者荣耀”,发现没有问题,那么第二页呢?将上面代码中的 url = "" 改为 url = ""

  再次搜索第二页“炉石传说”,发现没找到,那么网站可能是动态加载的

  2.2 解析json

  复制一段json过来

  {"count":2000, "data":<br /> [<br /> {"appId":108048, "displayName":"王者荣耀", "icon":"http://file.market.xiaomi.com/thumbnail/PNG/l62/AppStore/0eb7aa415046f4cb838cfe5b5d402a5efc34fbb25", "level1CategoryName":"网游RPG", "packageName":"com.tencent.tmgp.sgame"<br /> },<br /> {},<br /> ...<br /> ]<br />}

  不知道所有信息是干什么用的,暂时保存一下

  2.3 个二级页面

  点击“王者荣耀”跳转到APP详情,看看网址长什么样

  然后你会惊奇的发现id的查询参数和上面packageName的值是一样的,所以详情页需要拼接URL

  2.4 获取信息2.4 确认技术

  从上面的分析可以得出结论,使用lxml提取数据会是一个不错的选择。 xpath的使用请点击跳转

  xpath语法如下:

  3.代码实现

  import requestsfrom lxml import etreeclass MiSpider(object):<br /> def __init__(self):<br /> self.bsase_url = "http://app.mi.com/categotyAllListApi?page={}&categoryId=15&pageSize=30" # 一级页面的URL地址<br /> self.headers = {"User-Agent":"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} # 获取响应对象<br /> def get_page(self, url):<br /> reponse = requests.get(url=url, headers=self.headers) return reponse # 解析一级页面,即json解析,得到APP详情页的链接<br /> def parse_page(self, url):<br /> html = self.get_page(url).json() # two_url_list:[{"appId":"108048","dispayName":"..",...},{},{},...]<br /> two_url_list = html["data"] for two_url in two_url_list:<br /> two_url = "http://app.mi.com/details?id={}".format(two_url["packageName"]) # 拼接app详情链接<br /> self.parse_info(two_url) # 解析二级页面,得到名称、简介、下载链接<br /> def parse_info(self, two_url):<br /> html = self.get_page(two_url).content.decode("utf-8")<br /> parse_html = etree.HTML(html) # 获取目标信息<br /> app_name = parse_html.xpath('//div[@class="intro-titles"]/h3/text()')[0].strip()<br /> app_info = parse_html.xpath('//p[@class="pslide"][1]/text()')[0].strip()<br /> app_url = "http://app.mi.com" + parse_html.xpath('//a[@class="download"]/@href')[0].strip()<br /><br /> print(app_name, app_url, app_info) # 主函数<br /> def main(self):<br /> for page in range(67):<br /> url = self.bsase_url.format(page)<br /> self.parse_page(url)if __name__ == "__main__":<br /> spider = MiSpider()<br /> spider.main()

  接下来,存储数据,存储csv、MySQL、MongoDB的方式有很多种

  数据存储

  

  这里使用MySQL数据库来存储

  创建表 SQL

  /*<br /> Navicat MySQL Data Transfer<br /> Source Server : xxx<br /> Source Server Type : MySQL<br /> Source Server Version : 50727<br /> Source Host : MySQL_ip:3306<br /> Source Schema : MIAPP<br /> Target Server Type : MySQL<br /> Target Server Version : 50727<br /> File Encoding : 65001<br /> Date: 13/09/2019 14:33:38<br />*/<br /><br />CREATE DATABASE MiApp CHARSET=UTF8;<br /><br />SET NAMES utf8mb4;<br />SET FOREIGN_KEY_CHECKS = 0;<br /><br />-- ----------------------------<br />-- Table structure for app<br />-- ----------------------------<br />DROP TABLE IF EXISTS `app`;<br />CREATE TABLE `app` (<br /> `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APP名称',<br /> `url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APP下载链接',<br /> `info` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'APP简介'<br />) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;<br /><br />SET FOREIGN_KEY_CHECKS = 1;

  1.pymysql

  简单介绍pymysql的使用。这个模块是第三方的,需要用pip安装。安装方法不再赘述。

  1.1个内置方法

  pymysql方法

  pymysql 对象方法

  1.2 条笔记

  只要涉及到数据修改操作,就必须提交事务到数据库

  查询数据库需要使用fet方法获取查询结果

  1.3 详细信息

  更多详情请参考pymsql

  2.存储

  创建配置文件(config.py)

  '''<br />数据库连接信息<br />'''HOST = "xxx.xxx.xxx.xxx"PORT = 3306USER = "xxxxx"PASSWORD = "xxxxxxx"DB = "MIAPP"CHARSET = "utf8mb4"

  表结构

  mysql> desc MIAPP.app;<br />+-------+--------------+------+-----+---------+-------+<br />| Field | Type | Null | Key | Default | Extra |<br />+-------+--------------+------+-----+---------+-------+<br />| name | varchar(20) | YES | | NULL | |<br />| url | varchar(255) | YES | | NULL | |<br />| info | text | YES | | NULL | |<br />+-------+--------------+------+-----+---------+-------+3 rows in set (0.00 sec)

  SQL 语句

  insert into app values(name,url,info);

  完整代码

  import requestsfrom lxml import etreeimport pymysqlfrom config import *class MiSpider(object):<br /> def __init__(self):<br /> self.bsase_url = "http://app.mi.com/categotyAllListApi?page={}&categoryId=15&pageSize=30" # 一级页面的URL地址<br /> self.headers = {"User-Agent":"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}<br /> self.db = pymysql.connect(host=HOST, port=PORT, user=USER, password=PASSWORD, database=DB, charset=CHARSET) # 连接数据库<br /> self.cursor = self.db.cursor() # 创建游标<br /> self.i = 0 # 用来计数,无其他作用<br /><br /> # 获取响应对象<br /> def get_page(self, url):<br /> reponse = requests.get(url=url, headers=self.headers) return reponse # 解析一级页面,即json解析,得到APP详情页的链接<br /> def parse_page(self, url):<br /> html = self.get_page(url).json() # two_url_list:[{"appId":"108048","dispayName":"..",...},{},{},...]<br /> two_url_list = html["data"] for two_url in two_url_list:<br /> two_url = "http://app.mi.com/details?id={}".format(two_url["packageName"]) # 拼接app详情链接<br /> self.parse_info(two_url) # 解析二级页面,得到名称、简介、下载链接<br /> def parse_info(self, two_url):<br /> html = self.get_page(two_url).content.decode("utf-8")<br /> parse_html = etree.HTML(html) # 获取目标信息<br /> app_name = parse_html.xpath('//div[@class="intro-titles"]/h3/text()')[0].strip()<br /> app_info = parse_html.xpath('//p[@class="pslide"][1]/text()')[0].strip()<br /> app_url = "http://app.mi.com" + parse_html.xpath('//a[@class="download"]/@href')[0].strip()<br /><br /> ins = "insert into app(name,url,info) values (%s,%s,%s)" # 需要执行的SQL语句<br /><br /> self.cursor.execute(ins, [app_name, app_url, app_info])<br /><br /> self.db.commit()<br /><br /> self.i += 1<br /> print("第{}APP {}成功写入数据库".format(self.i, app_name)) # 主函数<br /> def main(self):<br /> for page in range(67):<br /> url = self.bsase_url.format(page)<br /> self.parse_page(url) # 断开数据库<br /> self.cursor.close()<br /> self.db.close()<br /><br /> print("执行结束,共{}个APP成功写入".format(self.i))if __name__ == "__main__":<br /> spider = MiSpider()<br /> spider.main()

  多线程

  爬取上面的信息好像有点慢,数据多的话太费时间了,电脑资源没有充分利用

  这需要多线程的概念。网上多进程多线程的概念比比皆是,只需要了解一点就行了

  一个进程可以收录多个线程,如果进程死了,线程就不再存在了

  

  比如,假设有一个列优采云,如果把这个列优采云理解为一个进程,那么每辆汽车就是一个线程,就是这么多线程共同组成了一个进程

  python中多线程的概念

  假设现在有两个操作:

  n += 1n -= 1

  它实际上在 python 中是这样工作的

  x = n<br />x = n + 1n = x<br /><br />x = n<br />x = n + 1n = x

  线程有一个特点,就是它们竞争计算机资源。如果一个线程刚刚计算了x=n,而另一个线程n=x在运行,那么就会全部搞砸了,也就是n加一千个1减去千个1的结果不一定是1。此时时间,考虑线程锁定问题。

  每个线程在运行时都会竞争共享数据。如果线程A正在操作一条数据,此时线程B也会操作该数据,可能会造成数据乱序,影响整个程序的运行。

  所以 Python 有一个机制。当一个线程工作时,它会锁定整个解释器,使其他线程无法访问任何资源。这种锁称为 GIL 全局解释器锁。正是因为这个锁的存在,名义上的多线程实际上变成了单线程,所以很多人把GIL称为python鸡肋的存在。

  针对这个缺陷,很多标准库和第三方模块或库都是基于这个缺陷开发的,这使得Python在多线程方面的改进尤其困难。在实际开发中,遇到这个问题我目前使用了四种解决方案:

  如果需要全面了解并发,请点击并发编程,这里只是简单介绍使用

  1.队列方法

  # 导入模块from queue import Queue# 使用q = Queue()<br />q.put(url)<br />q.get() # 当队列为空时,阻塞q.empty() # 判断队列是否为空,True/False

  2.线程方法

  # 导入模块from threading import Thread# 使用流程t = Thread(target=函数名) # 创建线程对象t.start() # 创建并启动线程t.join() # 阻塞等待回收线程# 创建多线程for i in range(5):<br /> t = Thread(target=函数名)<br /> t.start()<br /> t.join()

  3.重写

  了解了以上内容,就可以多线程重写原代码了,改写前要时不时补充

  多线程技术选择:

  线程池的设计:

  def url_in(self):<br /> for page in range(67):<br /> url = self.bsase_url.format(page)<br /> self.q.put(page)

  下面的完整代码

  import requestsfrom lxml import etreeimport timefrom threading import Threadfrom queue import Queueimport jsonimport pymysqlfrom config import *class MiSpider(object):<br /> def __init__(self):<br /> self.url = "http://app.mi.com/categotyAllListApi?page={}&categoryId=15&pageSize=30"<br /> self.headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3895.5 Safari/537.36"} # 创建URL队列<br /> self.url_queue = Queue() # 把所有要爬取的页面放进队列<br /> def url_in(self):<br /> for page in range(67):<br /> url = self.url.format(page) # 加入队列<br /> self.url_queue.put(url) # 线程事件函数<br /> def get_data(self):<br /> while True: # 如果结果 为True,则队列为空了<br /> if self.url_queue.empty(): break<br /> # get地址,请求一级页面<br /> url = self.url_queue.get()<br /> html = requests.get(url=url, headers=self.headers).content.decode("utf-8")<br /> html = json.loads(html) # 转换为json格式<br /> # 解析数据<br /> app_list = [] # 定义一个列表,用来保存所有的APP信息 [(name,url,info),(),(),...]<br /> for app in html["data"]: # 应用链接<br /> app_link = "http://app.mi.com/details?id=" + app["packageName"]<br /> app_list.append(self.parse_two_page(app_link)) return app_list def parse_two_page(self, app_link):<br /> html = requests.get(url=app_link, headers=self.headers).content.decode('utf-8')<br /> parse_html = etree.HTML(html)<br /><br /> app_name = parse_html.xpath('//div[@class="intro-titles"]/h3/text()')[0].strip()<br /> app_url = "http://app.mi.com" + parse_html.xpath('//div[@class="app-info-down"]/a/@href')[0].strip()<br /> app_info = parse_html.xpath('//p[@class="pslide"][1]/text()')[0].strip()<br /><br /> info = (app_name, app_url, app_info)<br /><br /> print(app_name) return info # 主函数<br /> def main(self):<br /> # url入队列<br /> self.url_in() # 创建多线程<br /> t_list = [] for i in range(67):<br /> t = Thread(target=self.get_data)<br /> t_list.append(t)<br /> t.start() for i in t_list:<br /> i.join()<br /><br /> db = pymysql.connect(host=HOST, user=USER, password=PASSWORD, database=DB, charset=CHARSET)<br /> cursor = db.cursor()<br /><br /> ins = 'insert into app values (%s, %s, %s)'<br /><br /> app_list = self.get_data()<br /> print("正在写入数据库")<br /> cursor.executemany(ins, app_list)<br /><br /> db.commit()<br /> cursor.close()<br /> db.close()if __name__ == '__main__':<br /> start = time.time()<br /> spider = MiSpider()<br /> spider.main()<br /> end = time.time()<br /><br /> print("执行时间:%.2f"% (end - start))

  当然,这里的设计理念是将URL放入队列,也可以将解析保存写入线程,提高程序的执行效率。

  点击访问了解更多爬虫技术

  欢迎大家互相交流

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线