数据获取——爬虫(下)
5.静态、动态网站的区别和应对
5.1区分静态、动态网站
静态网站的特点:
静态网站是最初的建站方式,浏览者所看到的每个页面是建站者上传到服务器上的一个 html ( htm )文件,这种网站每增加、删除、修改一个页面,都必须重新对服务器的文件进行一次下载上传。
网页内容一经发布到网站服务器上,无论是否有用户访问,每个静态网页的内容都是保存在网站服务器上的,也就是说,静态网页是实实在在保存在服务器上的文件,每个网页都是一个独立的文件。
-
静态网页的内容相对稳定,因此容易被搜索引擎检索。
-
静态网页没有数据库的支持,在网站制作和维护方面工作量较大,因此当网站信息量很大时完全依靠静态网页制作方式比较困难。
-
静态网页的交互性较差,在功能方面有较大的限制。
通俗来说,静态网页是指存放在服务器文件系统中实实在在的HTML文件。当用户在浏览器中输入页面的URL,然后回车,浏览器就会将对应的HTML文件下载、渲染并呈现在窗口中。早期的网站通常都是由静态页面制作的。

动态网站的特点:
动态网站在页面里嵌套了程序,这种网站对一些框架相同、更新较快的信息页面进行内容与形式的分离,将信息内容以记录的形式存入网站的数据库中,以便于网站各处的调用。
动态网页是相对于静态网页而言的。当浏览器请求服务器的某个页面时,服务器根据当前时间、环境参数、数据库操作等动态的生成HTML页面,然后在发送给浏览器(后面的处理就跟静态网页一样了)。
很明显,动态网页中的“动态"是指服务器端页面的动态生成,相反,"静态"则指页面是实实在在的、独立的文件。
这里说的动态网页,与网页上的各种动画、滚动字幕等视觉上的 “ 动态效果 ” 没有直接关系,动态网页也可以是纯文字内容的,也可以是包含各种动画的内容,这些只是网页具体内容的表现形式,无论网页是否具有动态效果,采用动态网站技术生成的网页都称为动态网页。
从网站浏览者的角度来看,无论是动态网页还是静态网页,都可以展示基本的文字和图片信息,但从网站开发、管理、维护的角度来看就有很大的差别。
动态网页的特点归纳如下:
-
动态网页以数据库技术为基础,可以大大降低网站维护的工作量 ;
-
采用动态网页技术的网站可以实现更多的功能,如用户注册、用户登录、在线调查、用户管理、订单管理等等 ;
-
动态网页实际上并不是独立存在于服务器上的网页文件,只有当用户请求时服务器才返回一个完整的网页 ;
注意:
动态页面技术是与静态页面技术相对应的,也就是说,网页URL的后缀不是.htm、.html、.shtml、.xml等静态网页的常见形式,而是以.asp、.jsp、.php、.perl、.cgi等形式为后缀,并且在动态网页网址中有一个标志性的符号——“? "。
这里说的动态网页,与网页上的各种动画、滚动字幕等视觉上的“动态效果"没有直接关系,动态网页也可以是纯文字内容的,也可以是包含各种动画的内容,这些只是网页具体内容的表现形式,无论网页是否具有动态效果,采用动态网站技术生成的网页都称为动态网页。
5.2静态网站解析流程
① 你要爬取的网站是什么?
② 你要爬取页面上的哪些信息?
③ 页面是 “静态网页”,还是“动态网页”?
那么它们的区别就在于: 静态网页中的数据,是一次性给你。动态网页中的数据,是随着页面一步步加载出来,而逐步呈现的,也就是你用静态网页的爬虫技术,无法获取到里面所有的数据。
实例提取电视台收视率:
import csv # 用于数据存储 import requests # 用于请求网页 import chardet # 用于修改编码 import re # 用于提取数据 from lxml import etree # 解析数据的库 import time # 可以粗糙模拟人为请求网页的速度 import warnings # 忽略代码运行时候的警告信息 warnings.filterwarnings("ignore") def get_data(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'} rqg = requests.get(url, headers=headers, verify=False) # a rqg.encoding = chardet.detect(rqg.content)['encoding'] # b html = etree.HTML(rqg.text) # 1. 标题 title = html.xpath('//header[@class="entry-header"]/table/tbody/tr/td[2]/font/h2/a/@title') # 2. 发布时间 date = html.xpath('//header[@class="entry-header"]/table/tbody/tr/td[2]/div/time/text()') # 3. 链接 link = html.xpath('//header[@class="entry-header"]/table/tbody/tr/td[2]/font/h2/a/@href') return title, date, link def main(): x = "http://www.tvtv.hk/archives/category/tv/page/" url_list = [x + str(i) for i in range(1,11)] headers = ['标题','发布时间','链接'] values = [] titles = [] dates = [] links = [] for url in url_list: print('>> 正获取: ',url) title, date, link = get_data(url) for t in title: titles.append(t) for d in date: dates.append(d) for l in link: links.append(l) time.sleep(3) # 加时间延迟,减少访问频率 for i in range(len(titles)): value = [titles[i],dates[i],links[i]] values.append(value) with open('电视台.csv','w',newline='') as fp: # 获取对象 writer = csv.writer(fp) # 写入数据 writer.writerow(headers) #写入表头 writer.writerows(values) # 写入数据 if __name__=='__main__': main()
6.动态网站分析
常见的动态网页技术:JavaScript、Ajax、DHTML
使用动态加载的网站,用Python解决有如下几种途径:
-
直接破解JavaScript代码里采集内容,即js逆向;
-
抓包分析,查看截图的请求响应信息,伪造请求,实现响应的获取,即找到真实加载数据的动态链接;
-
用Python的第三方库运行JavaScript,直接采集你在浏览器里看到的页面,即模拟登录;
6.1Ajax加载的动态网站分析
有时候我们在用 requests 抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但是使用 requests 得到的结果并没有。这是因为 requests 获取的都是原始的 HTML 文档,而浏览器中的页面则是经过 JavaScript 处理数据后生成的结果,这些数据的来源有多种,可能是通过 Ajax 加载的,可能是包含在 HTML 文档中的,也可能是经过 JavaScript 和特定算法计算后生成的。
对于第一种情况,数据加载是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面加载完后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现到网页上,这其实就是发送了一个 Ajax 请求。
所以如果遇到这样的页面,直接利用 requests 等库来抓取原始页面,是无法获取到有效数据的,这时需要分析网页后台向接口发送的 Ajax 请求,如果可以用 requests 来模拟 Ajax 请求,那么就可以成功抓取了。
import requests headers = { 'authority': 'api.qimai.cn', 'sec-ch-ua': '"Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua-mobile': '?0', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36', 'sec-ch-ua-platform': '"Windows"', 'origin': 'https://www.qimai.cn', 'sec-fetch-site': 'same-site', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://www.qimai.cn/', 'accept-language': 'zh-CN,zh;q=0.9', 'cookie': 'qm_check=SxJXQEUSChd2fHd1dRQQeV5EVVwcEHxZRlVVGGYREGV4dBB3QlRHWllaQxQOAgAQdFlCVVZDAXQIARROQ28FbwAQQEZoB28JHBR8A3QBAR0CAhsFAh4IBhoMBwAIGRIcElZfV1NSEg4aABwAHAAcABkHEE0%3D; gr_user_id=9ef08b21-8dd7-45f0-8c40-88996def62ec; USERINFO=zcXe0A9c7kmLDlPofA%2FnW6%2Fi0Vnf0iA1hg7SRijWXCD8N4AMklWRp4k9WlYvFCkziUdIlH7KTirUSklRPhSZGHLBY3fxLkORNX3KOso0WSnvf9i9KuRh4V8ddjeG0v%2BdSSm08lrJ55qInpKRd8%2BOzA%3D%3D; AUTHKEY=snHdCWmpZLSo9%2BAU1RQgKbDLcKvIfHg%2FUKgzMC92wsIUzanyQBD529MAujOMU%2BWyN9il0RH0o%2BycPNGb6jDmvbP2Uj5w1ydWA%2FteweJu0ziZ6TbqfL%2Bs%2FA%3D%3D; ada35577182650f1_gr_last_sent_cs1=qm10437503601; aso_ucenter=360bynVy6wNu9y4%2BH0gQasBLv2hH72JBvq3j2Q59OpTYoSF62HCcKfBwHaSk3sZn4A; PHPSESSID=p34ufc1vdab8q2edo34diq3rdc; ada35577182650f1_gr_session_id=922e8346-72fe-45be-b349-54deb6a8e6f5; ada35577182650f1_gr_last_sent_sid_with_cs1=922e8346-72fe-45be-b349-54deb6a8e6f5; ada35577182650f1_gr_session_id_922e8346-72fe-45be-b349-54deb6a8e6f5=true; tgw_l7_route=d09474674af82c17375cfcdd775c0c28; synct=1634137296.468; syncd=823; ada35577182650f1_gr_cs1=qm10437503601', } params = ( ('analysis', 'dQ59QSxadUR9ZHFEdTB6QipZcBJSd35FUWhyVwYFDQh0FU5CUV5bH1leXAFPaAhBRU5SQlFeVG9ZXEsGeEcFB1gAAQEGBQEDCVF3G1U='), ('brand', 'all'), ('country', 'cn'), ('device', 'iphone'), ('genre', '36'), ('date', '2021-10-13'), ('page', '2'), ) try: response = requests.get('https://api.qimai.cn/rank/indexPlus/brand_id/1', headers=headers, params=params) if response.status_code == 200: print('请求成功') print(response.json()) except requests.ConnectionError as e: print('Error', e.args) lists = response.json()['list'] results = [] for i in lists: result = {} result['APP'] = i['appInfo']['appName'] result['类型'] = i['genre'] result['公司'] = i['appInfo']['publisher'] result['排名'] = i['index'] print(result) results.append(result)
7.反爬
因为爬虫技术造成的大量IP访问网站侵占带宽资源、以及用户隐私和知识产权等危害,很多互联网企业都会花大力气进行“反爬虫”。爬虫会遭遇比如被网站封IP、比如各种奇怪的验证码、userAgent访问限制、各种动态加载、post请求参数动态变化、禁止页面调试等都有可能出现。
常见的反爬虫措施有:
- 登录验证、验证码、滑块
- 登录请求参数token
- 通过Headers反爬虫
- 基于用户行为反爬虫
- 基于动态页面的反爬虫
- 字体反爬
- .......
反反爬的主要思路:尽可能的去模拟浏览器,浏览器在如何操作,代码中就如何去实现。
7.1请求头:User-agent
在这里的User-Agent可以使用多个随机的,意识就是假如你请求20次,你可以自己构造多个不同的User-Agent随机使用一次不重样的,防止过于频繁,这也是常见的方式。
1、可以使用fake-useragent库来实现随机更换User-Agent
2、自行从这个网站收集: http://useragent.kuzhazha.com/
3、自行构建,如下
import random def get_ua(): first_num = random.randint(55, 62) third_num = random.randint(0, 3200) fourth_num = random.randint(0, 140) os_type = [ '(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)', '(Macintosh; Intel Mac OS X 10_12_6)' ] chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num) ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36', '(KHTML, like Gecko)', chrome_version, 'Safari/537.36'] ) return ua print(get_ua())
7.2 通过referer字段或者是其他字段来反爬
反爬原理:爬虫默认情况下不会带上referer字段
解决方法:添加referer字段
7.3通过cookie来反爬
如果目标网站不需要登录 每次请求带上前一次返回的cookie,比如requests模块的session 如果目标网站需要登录,
则准备多个账号,通过一个程序获取账号对应的cookie,组成cookie池,其他程序使用这些cookie.
7.4通过js来反爬
普通的爬虫默认情况下无法执行js,获取js执行之后的结果,所以很多时候对方服务器会通过js的技术实现反爬
1.找到debug的函数,禁止调用它,我们就可以正常调试了

2.通过js生成了请求参数

解决方法:分析js,观察加密的实现过程,这里就涉及到js逆向的知识了,或者使用selenium动态加载来实现,但这种方法局限性很大
3.通过js实现了数据的加密

解决方法:分析js,观察加密的实现过程,通过js2py获取js的执行结果,或者使用selenium来实现
7.5通过验证码来反爬
反爬原理:对方服务器通过弹出验证码强制验证用户浏览行为
解决方法:打码平台或者是机器学习的方法识别验证码,其中打码平台廉价易用,更值得推荐,不过如果是遇到简单的数字验证码或者滑块都是可以自行去解决的。
参考链接: 爬虫大佬 - Heywhale.com
https://www.cnblogs.com/Amy-is-a-fish-yeah/p/11788464.html

浙公网安备 33010602011771号