
ajax抓取网页内容
解决方案:ajax抓取网页内容属性控制用什么请求方式(get/post)
网站优化 • 优采云 发表了文章 • 0 个评论 • 187 次浏览 • 2022-09-21 17:10
ajax抓取网页内容,就是通过get请求的方式向服务器写入数据,实现网页的高效抓取。body属性控制用什么请求方式(get/post)。为一个字符串时可以使用charset属性将charset对象设置为utf-8。body的内容中需要加上data就变成了body_data。这里fromxxximportajax,urlfromxxximportbody,data。
body通常是要加上data的
ajax写的时候一般就有url的字段。可以用@框架的方式,可以走xmlhttprequest模式也可以走https模式的,看项目情况。其他的一般都是通过@可以用get/post等方式实现。
谢邀post/get/data/text/content/plain这几种就可以加上自己想加的内容,当然有时候加了也没有用,因为ajax的内容比较多,且多是一些资料性的内容,因此就为你支两招吧servlet的话,ajax容器里的service里面(tomcat里的inner类中)一般都会有一个url的字段,在它的url中我们可以输入自己想要的内容,这些内容就需要放在body中去了。
看了上面四个答案,问题都差不多,但是有一个很关键的问题没人给到答案:content-type,在form表单中,内容是放在form里的,无论他写的是什么。只有用ajax才可以变成页面上,只有在这里才可以!一般情况下http数据发过来以后,不管它是getpostputdelete还是直接post到服务器,最后都会转换成form表单发回给服务器,所以,所有请求数据的格式都是post或get的。请求服务器的格式:返回数据一般用json格式,再加上对方响应的数据的json格式即可。 查看全部
解决方案:ajax抓取网页内容属性控制用什么请求方式(get/post)
ajax抓取网页内容,就是通过get请求的方式向服务器写入数据,实现网页的高效抓取。body属性控制用什么请求方式(get/post)。为一个字符串时可以使用charset属性将charset对象设置为utf-8。body的内容中需要加上data就变成了body_data。这里fromxxximportajax,urlfromxxximportbody,data。

body通常是要加上data的
ajax写的时候一般就有url的字段。可以用@框架的方式,可以走xmlhttprequest模式也可以走https模式的,看项目情况。其他的一般都是通过@可以用get/post等方式实现。

谢邀post/get/data/text/content/plain这几种就可以加上自己想加的内容,当然有时候加了也没有用,因为ajax的内容比较多,且多是一些资料性的内容,因此就为你支两招吧servlet的话,ajax容器里的service里面(tomcat里的inner类中)一般都会有一个url的字段,在它的url中我们可以输入自己想要的内容,这些内容就需要放在body中去了。
看了上面四个答案,问题都差不多,但是有一个很关键的问题没人给到答案:content-type,在form表单中,内容是放在form里的,无论他写的是什么。只有用ajax才可以变成页面上,只有在这里才可以!一般情况下http数据发过来以后,不管它是getpostputdelete还是直接post到服务器,最后都会转换成form表单发回给服务器,所以,所有请求数据的格式都是post或get的。请求服务器的格式:返回数据一般用json格式,再加上对方响应的数据的json格式即可。
Python入门网络爬虫之精华版
网站优化 • 优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-09-11 10:45
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
转载:宁哥的小站»Python入门网络爬虫之精华版
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
Requests:<br /> import requests<br /> response = requests.get(url)<br /> content = requests.get(url).content<br /> print "response headers:", response.headers<br /> print "content:", content<br />Urllib2:<br /> import urllib2<br /> response = urllib2.urlopen(url)<br /> content = urllib2.urlopen(url).read()<br /> print "response headers:", response.headers<br /> print "content:", content<br />Httplib2:<br /> import httplib2<br /> http = httplib2.Http()<br /> response_headers, content = http.request(url, 'GET')<br /> print "response headers:", response_headers<br /> print "content:", content<br />
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.get(url=url, params=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> full_url = url+'?'+data<br /> response = urllib2.urlopen(full_url)<br />
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.post(url=url, data=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> req = urllib2.Request(url=url, data=data)<br /> response = urllib2.urlopen(req)<br />
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
import requests <br />requests_session = requests.session() <br />response = requests_session.post(url=url_login, data=data)<br />
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
response_captcha = requests_session.get(url=url_login, cookies=cookies)<br />response1 = requests.get(url_login) # 未登陆<br />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br />
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br />Requests:<br /> import requests<br /> response = requests.get(url=url, proxies=proxies)<br />Urllib2:<br /> import urllib2<br /> proxy_support = urllib2.ProxyHandler(proxies)<br /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br /> response = urllib2.urlopen(url)<br />
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
import time<br />time.sleep(1)<br />
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br />headers = {'Referer':'XXXXX'}<br />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br />Requests:<br /> response = requests.get(url=url, headers=headers)<br />Urllib2:<br /> import urllib, urllib2 <br /> req = urllib2.Request(url=url, headers=headers)<br /> response = urllib2.urlopen(req)<br />
4. 对于断线重连
def multi_session(session, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return session.post(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
或者
def multi_open(opener, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return opener.open(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
禁止所有机器人访问<br /> User-agent: *<br /> Disallow: /<br />允许所有机器人访问<br /> User-agent: *<br /> Disallow: <br />禁止特定机器人访问<br /> User-agent: BadBot<br /> Disallow: /<br />允许特定机器人访问<br /> User-agent: GoodBot<br /> Disallow: <br />禁止访问特定目录<br /> User-agent: *<br /> Disallow: /images/<br />仅允许访问特定目录<br /> User-agent: *<br /> Allow: /images/<br /> Disallow: /<br />禁止访问特定文件<br /> User-agent: *<br /> Disallow: /*.html$<br />仅允许访问特定文件<br /> User-agent: *<br /> Allow: /*.html$<br /> Disallow: /<br /> <br /> 查看全部
Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
转载:宁哥的小站»Python入门网络爬虫之精华版
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
Requests:<br /> import requests<br /> response = requests.get(url)<br /> content = requests.get(url).content<br /> print "response headers:", response.headers<br /> print "content:", content<br />Urllib2:<br /> import urllib2<br /> response = urllib2.urlopen(url)<br /> content = urllib2.urlopen(url).read()<br /> print "response headers:", response.headers<br /> print "content:", content<br />Httplib2:<br /> import httplib2<br /> http = httplib2.Http()<br /> response_headers, content = http.request(url, 'GET')<br /> print "response headers:", response_headers<br /> print "content:", content<br />
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.get(url=url, params=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> full_url = url+'?'+data<br /> response = urllib2.urlopen(full_url)<br />
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.post(url=url, data=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> req = urllib2.Request(url=url, data=data)<br /> response = urllib2.urlopen(req)<br />
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。

import requests <br />requests_session = requests.session() <br />response = requests_session.post(url=url_login, data=data)<br />
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
response_captcha = requests_session.get(url=url_login, cookies=cookies)<br />response1 = requests.get(url_login) # 未登陆<br />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br />
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br />Requests:<br /> import requests<br /> response = requests.get(url=url, proxies=proxies)<br />Urllib2:<br /> import urllib2<br /> proxy_support = urllib2.ProxyHandler(proxies)<br /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br /> response = urllib2.urlopen(url)<br />
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
import time<br />time.sleep(1)<br />
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br />headers = {'Referer':'XXXXX'}<br />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br />Requests:<br /> response = requests.get(url=url, headers=headers)<br />Urllib2:<br /> import urllib, urllib2 <br /> req = urllib2.Request(url=url, headers=headers)<br /> response = urllib2.urlopen(req)<br />
4. 对于断线重连
def multi_session(session, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return session.post(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
或者
def multi_open(opener, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return opener.open(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。

这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
禁止所有机器人访问<br /> User-agent: *<br /> Disallow: /<br />允许所有机器人访问<br /> User-agent: *<br /> Disallow: <br />禁止特定机器人访问<br /> User-agent: BadBot<br /> Disallow: /<br />允许特定机器人访问<br /> User-agent: GoodBot<br /> Disallow: <br />禁止访问特定目录<br /> User-agent: *<br /> Disallow: /images/<br />仅允许访问特定目录<br /> User-agent: *<br /> Allow: /images/<br /> Disallow: /<br />禁止访问特定文件<br /> User-agent: *<br /> Disallow: /*.html$<br />仅允许访问特定文件<br /> User-agent: *<br /> Allow: /*.html$<br /> Disallow: /<br /> <br />
ajax+ajax的内容存储在服务器.获取网页内容
网站优化 • 优采云 发表了文章 • 0 个评论 • 45 次浏览 • 2022-09-06 14:01
ajax抓取网页内容,一般是用js脚本去获取网页内容,特别是直接用requests去请求获取网页内容,然后经过编码,转化成json,然后存储。
就是请求服务器啊.每个请求都会定时分析这个html,用正则表达式匹配出某个元素,
ajax技术能够将javascript与网页交互的方式转化为json,然后再解析出页面的内容和跳转地址。ajax技术的提出,源于当时流行的html5标准。而html5标准中也提到了xmlhttprequest,即后来的ajax。使用xmlhttprequest来发送数据有三个标准可以选择,它们是activex,jsonp,xml2。
但是activex和jsonp并不兼容,只能推荐使用xml2来发送xml数据。jsonp也不能充分利用xmlhttprequest发送ajax消息。于是w3c发布了requests库来发送xml消息。后来还提供了xml2的xmlhttprequestapi。
ajax就是xmlhttprequest+ajax的json转换器这个node.js可以用
ajax在javascript技术层面是json的一种类型。
ajax既然名为“asynchronousjavascriptxmlretransform”,那么应该是同时发送两个html,xml的内容存储在服务器,json的内容存储在浏览器.
获取网页内容?显然是获取xml.那就要json.parse了。至于如何写出一个合格的xml/json/xml.js,js其实可以写很长很复杂的程序,可以有很多种。大多数情况下,只需要用框架(servlet,jstl,fiber), 查看全部
ajax+ajax的内容存储在服务器.获取网页内容
ajax抓取网页内容,一般是用js脚本去获取网页内容,特别是直接用requests去请求获取网页内容,然后经过编码,转化成json,然后存储。
就是请求服务器啊.每个请求都会定时分析这个html,用正则表达式匹配出某个元素,

ajax技术能够将javascript与网页交互的方式转化为json,然后再解析出页面的内容和跳转地址。ajax技术的提出,源于当时流行的html5标准。而html5标准中也提到了xmlhttprequest,即后来的ajax。使用xmlhttprequest来发送数据有三个标准可以选择,它们是activex,jsonp,xml2。
但是activex和jsonp并不兼容,只能推荐使用xml2来发送xml数据。jsonp也不能充分利用xmlhttprequest发送ajax消息。于是w3c发布了requests库来发送xml消息。后来还提供了xml2的xmlhttprequestapi。
ajax就是xmlhttprequest+ajax的json转换器这个node.js可以用

ajax在javascript技术层面是json的一种类型。
ajax既然名为“asynchronousjavascriptxmlretransform”,那么应该是同时发送两个html,xml的内容存储在服务器,json的内容存储在浏览器.
获取网页内容?显然是获取xml.那就要json.parse了。至于如何写出一个合格的xml/json/xml.js,js其实可以写很长很复杂的程序,可以有很多种。大多数情况下,只需要用框架(servlet,jstl,fiber),
ajax抓取网页内容的方法有很多种,ajax代理接口
网站优化 • 优采云 发表了文章 • 0 个评论 • 57 次浏览 • 2022-08-19 06:03
ajax抓取网页内容的方法有很多种,如果目标网站已经对返回正常内容做了requestlist的话,那么还可以通过爬虫代理接口完成抓取。如果网站还在对requestlist返回正常的话,在第一次抓取网页的时候,可以通过判断返回requestlist的规律完成抓取。首先判断他的返回requestlist的规律,可以通过这些规律获取这些返回的requestidxxxbooks/5000,比如做网络请求的sleep是1-3,抓取也要这样做,flooding可以做出最大点击次数,剩余抓取次数和最大点击次数差不多,通过flooding可以知道最大点击次数除以sleep来判断下一次抓取request的id有可能是多少。
然后判断get请求的返回结果是否与返回正常的不同,比如请求article.json来抓取,返回article的返回结果是两个字符串,一个是html,一个是json,那么可以试试把json转化成字符串再请求,这样抓取时就是没有返回json所对应的html内容,即从article转换出来的html里没有json字符串。
其他的爬虫代理也是这么判断的,先通过判断返回正常的返回结果来判断规律是否与返回requestlist不同再进行抓取操作。接下来可以爬取数据库里的数据,因为要抓取的对象都是由server生成请求记录的(类似爬虫请求请求记录),所以可以通过判断请求记录的规律,从数据库中直接爬取到该对象的access_token,通过这个access_token请求对象时,会被弹出验证码验证请求是否正确。最后根据规律取到这个对象的server。 查看全部
ajax抓取网页内容的方法有很多种,ajax代理接口

ajax抓取网页内容的方法有很多种,如果目标网站已经对返回正常内容做了requestlist的话,那么还可以通过爬虫代理接口完成抓取。如果网站还在对requestlist返回正常的话,在第一次抓取网页的时候,可以通过判断返回requestlist的规律完成抓取。首先判断他的返回requestlist的规律,可以通过这些规律获取这些返回的requestidxxxbooks/5000,比如做网络请求的sleep是1-3,抓取也要这样做,flooding可以做出最大点击次数,剩余抓取次数和最大点击次数差不多,通过flooding可以知道最大点击次数除以sleep来判断下一次抓取request的id有可能是多少。

然后判断get请求的返回结果是否与返回正常的不同,比如请求article.json来抓取,返回article的返回结果是两个字符串,一个是html,一个是json,那么可以试试把json转化成字符串再请求,这样抓取时就是没有返回json所对应的html内容,即从article转换出来的html里没有json字符串。
其他的爬虫代理也是这么判断的,先通过判断返回正常的返回结果来判断规律是否与返回requestlist不同再进行抓取操作。接下来可以爬取数据库里的数据,因为要抓取的对象都是由server生成请求记录的(类似爬虫请求请求记录),所以可以通过判断请求记录的规律,从数据库中直接爬取到该对象的access_token,通过这个access_token请求对象时,会被弹出验证码验证请求是否正确。最后根据规律取到这个对象的server。
ajax抓取网页内容,如何进行判断是否是转义符呢
网站优化 • 优采云 发表了文章 • 0 个评论 • 60 次浏览 • 2022-07-15 21:05
ajax抓取网页内容,如何进行判断是否是转义符呢?这里就需要我们掌握,ajax中的xmlhttprequest对象。publicclassthreadextendsserializable{privatestaticfinalintxhr=25;privatestaticfinalintxhrfile;privatestaticfinalintxhrread;privatestaticfinalintxhrtimeout;publicthread(stringname){super(name,name);}@overridepublicvoidrun(){system.out.println("请求一个资源");}}xmlhttprequest对象中定义了三个属性:name、fromserver、methods方法,其作用是判断请求属性。
publicclassxmlhttprequestextendshttpservletrequestimplementshttpservletrequestlistener{//是否是servlethttp请求,servlethttp请求是打开不了的privatestaticfinalintxhr=25;privatestaticfinalintxhrfile="s.html";privatestaticfinalintxhrworkinstance=4;publicxmlhttprequest(stringname){this.name=name;}@overridepublicvoidrun(){system.out.println("请求一个资源");}}以下代码检查一个xmlhttprequest请求是否成功。
contextxmlhttprequest=newcontext("c:\\users\\lieke\\administrator\\appdata\\microsoft\\xmlhttp");publicstaticvoidmain(string[]args){system.out.println("请求一个资源");contextxmlhttprequest.send(newstring("lyndlyyyyyyy"));}publicstaticvoidsend(newstring("lyndlyyyyyyy")){system.out.println("服务器收到请求,并把字符串回复给"+xmlhttprequest.getheader("location")+""+xmlhttprequest.getheader("username")+""+xmlhttprequest.getheader("password")+""+"enteryouraction");}。 查看全部
ajax抓取网页内容,如何进行判断是否是转义符呢

ajax抓取网页内容,如何进行判断是否是转义符呢?这里就需要我们掌握,ajax中的xmlhttprequest对象。publicclassthreadextendsserializable{privatestaticfinalintxhr=25;privatestaticfinalintxhrfile;privatestaticfinalintxhrread;privatestaticfinalintxhrtimeout;publicthread(stringname){super(name,name);}@overridepublicvoidrun(){system.out.println("请求一个资源");}}xmlhttprequest对象中定义了三个属性:name、fromserver、methods方法,其作用是判断请求属性。

publicclassxmlhttprequestextendshttpservletrequestimplementshttpservletrequestlistener{//是否是servlethttp请求,servlethttp请求是打开不了的privatestaticfinalintxhr=25;privatestaticfinalintxhrfile="s.html";privatestaticfinalintxhrworkinstance=4;publicxmlhttprequest(stringname){this.name=name;}@overridepublicvoidrun(){system.out.println("请求一个资源");}}以下代码检查一个xmlhttprequest请求是否成功。
contextxmlhttprequest=newcontext("c:\\users\\lieke\\administrator\\appdata\\microsoft\\xmlhttp");publicstaticvoidmain(string[]args){system.out.println("请求一个资源");contextxmlhttprequest.send(newstring("lyndlyyyyyyy"));}publicstaticvoidsend(newstring("lyndlyyyyyyy")){system.out.println("服务器收到请求,并把字符串回复给"+xmlhttprequest.getheader("location")+""+xmlhttprequest.getheader("username")+""+xmlhttprequest.getheader("password")+""+"enteryouraction");}。
【第195期】如何让搜索引擎抓取AJAX内容
网站优化 • 优采云 发表了文章 • 0 个评论 • 52 次浏览 • 2022-06-17 20:48
【早读君聊聊】公司产品用户的特殊性,所以在开发的时候都会顾及SEO的作用,也就是希望所开发的页面能被搜索引擎收录。但在SPA流行的年代,团队童鞋也是很希望尝试新模式,在各种冲突中做权衡,找合适的方案。
正文~~~~
越来越多的网站,开始采用"单页面结构"(Single-page application)。整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容。
这种做法的好处是用户体验好、节省流量,缺点是AJAX内容无法被搜索引擎抓取。举例来说,你有一个网站。
用户通过井号结构的URL,看到不同的内容。
但是,搜索引擎只抓取,不会理会井号,因此也就无法索引内容。为了解决这个问题,Google提出了"井号+感叹号"的结构。
当Google发现上面这样的URL,就自动抓取另一个网址:
只要你把AJAX内容放在这个网址,Google就会收录。但是问题是,"井号+感叹号"非常难看且烦琐。Twitter曾经采用这种结构。
它把
改成
结果用户抱怨连连,只用了半年就废除了。
那么,有没有什么方法,可以在保持比较直观的URL的同时,还让搜索引擎能够抓取AJAX内容?
我一直以为没有办法做到,直到前两天看到了Discourse创始人之一的Robin Ward的解决方法,不禁拍案叫绝。
Discourse是一个论坛程序,严重依赖Ajax,但是又必须让Google收录内容。它的解决方法就是放弃井号结构,采用 History API。所谓 History API,指的是不刷新页面的情况下,改变浏览器地址栏显示的URL(准确说,是改变网页的当前状态)。这里有一个例子,你点击上方的按钮,开始播放音乐。然后,再点击下面的链接,看看发生了什么事?
地址栏的URL变了,但是音乐播放没有中断!
History API 的详细介绍,超出这篇文章的范围。这里只简单说,它的作用就是在浏览器的History对象中,添加一条记录。
上面这行命令,可以让地址栏出现新的URL。History对象的pushState方法接受三个参数,新的URL就是第三个参数,前两个参数都可以是null。
目前,各大浏览器都支持这个方法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。
下面就是Robin Ward的方法。
首先,用History API替代井号结构,让每个井号都变成正常路径的URL,这样搜索引擎就会抓取每一个网页。
然后,定义一个JavaScript函数,处理Ajax部分,根据网址抓取内容(假定使用jQuery)。
再定义鼠标的click事件。
还要考虑到用户点击浏览器的"前进 / 后退"按钮。这时会触发History对象的popstate事件。
定义完上面三段代码,就能在不刷新页面的情况下,显示正常路径URL和AJAX内容。
最后,设置服务器端。
因为不使用井号结构,每个URL都是一个不同的请求。所以,要求服务器端对所有这些请求,都返回如下结构的网页,防止出现404错误。
仔细看上面这段代码,你会发现有一个noscript标签,这就是奥妙所在。
我们把所有要让搜索引擎收录的内容,都放在noscript标签之中。这样的话,用户依然可以执行AJAX操作,不用刷新页面,但是搜索引擎会收录每个网页的主要内容! 查看全部
【第195期】如何让搜索引擎抓取AJAX内容
【早读君聊聊】公司产品用户的特殊性,所以在开发的时候都会顾及SEO的作用,也就是希望所开发的页面能被搜索引擎收录。但在SPA流行的年代,团队童鞋也是很希望尝试新模式,在各种冲突中做权衡,找合适的方案。
正文~~~~
越来越多的网站,开始采用"单页面结构"(Single-page application)。整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容。
这种做法的好处是用户体验好、节省流量,缺点是AJAX内容无法被搜索引擎抓取。举例来说,你有一个网站。
用户通过井号结构的URL,看到不同的内容。
但是,搜索引擎只抓取,不会理会井号,因此也就无法索引内容。为了解决这个问题,Google提出了"井号+感叹号"的结构。
当Google发现上面这样的URL,就自动抓取另一个网址:
只要你把AJAX内容放在这个网址,Google就会收录。但是问题是,"井号+感叹号"非常难看且烦琐。Twitter曾经采用这种结构。
它把
改成
结果用户抱怨连连,只用了半年就废除了。
那么,有没有什么方法,可以在保持比较直观的URL的同时,还让搜索引擎能够抓取AJAX内容?
我一直以为没有办法做到,直到前两天看到了Discourse创始人之一的Robin Ward的解决方法,不禁拍案叫绝。
Discourse是一个论坛程序,严重依赖Ajax,但是又必须让Google收录内容。它的解决方法就是放弃井号结构,采用 History API。所谓 History API,指的是不刷新页面的情况下,改变浏览器地址栏显示的URL(准确说,是改变网页的当前状态)。这里有一个例子,你点击上方的按钮,开始播放音乐。然后,再点击下面的链接,看看发生了什么事?
地址栏的URL变了,但是音乐播放没有中断!
History API 的详细介绍,超出这篇文章的范围。这里只简单说,它的作用就是在浏览器的History对象中,添加一条记录。
上面这行命令,可以让地址栏出现新的URL。History对象的pushState方法接受三个参数,新的URL就是第三个参数,前两个参数都可以是null。
目前,各大浏览器都支持这个方法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。
下面就是Robin Ward的方法。
首先,用History API替代井号结构,让每个井号都变成正常路径的URL,这样搜索引擎就会抓取每一个网页。
然后,定义一个JavaScript函数,处理Ajax部分,根据网址抓取内容(假定使用jQuery)。
再定义鼠标的click事件。
还要考虑到用户点击浏览器的"前进 / 后退"按钮。这时会触发History对象的popstate事件。
定义完上面三段代码,就能在不刷新页面的情况下,显示正常路径URL和AJAX内容。
最后,设置服务器端。
因为不使用井号结构,每个URL都是一个不同的请求。所以,要求服务器端对所有这些请求,都返回如下结构的网页,防止出现404错误。
仔细看上面这段代码,你会发现有一个noscript标签,这就是奥妙所在。
我们把所有要让搜索引擎收录的内容,都放在noscript标签之中。这样的话,用户依然可以执行AJAX操作,不用刷新页面,但是搜索引擎会收录每个网页的主要内容!
动态网页抓不了?JavaScript入门攻略已发送~
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-06-17 20:48
var carname="Volvo";
0 3
变量命名的规则
① 由字母、数字、下划线和 $ 组成,但是不能以数字开头,如:12asd 这个名字就会报错
② 不能是关键字或保留字,比如 var、for等
③ 严格区分大小写,就是说大写和小写都是不一样的变量
0 4
数据类型
JavaScript 的数据类型分两种,一种是简单数据类型,另一种是复杂数据类型。
示例:返回的类型是一个number;
<br /> var a = 123; //var是设置一个变量 alert('hello') //一个弹窗,可以判断是否为外部引入的 console.log(a) //console.log():是在浏览器的控制台上的输出 console.log(typeof a); //typeof 判断是属于什么类型<br />
需要注意:要严格区分大小写,否则便会出现报错。
0 5
介绍几个函数
(1)Number() 将数据转换成number类型,里面的参数便是你要转变类型的数据。<br />(2)toString() String() 两种方法将数据转换成字符串类型;区别String() 可以将null 转换成"null" toString() 返回的是undefined;<br />(3)Boolean() 将数据类型转换换成布尔类型;bool 返回两种数据类型,一个是true 一个是false。在将 Boolean 类型转 Number 时,true会转为 1, false 会转为 0,这个方法不支持将数字开头带有其它字符的字符串转为数值类型,如 “12df”。
2 Python执行JS代码的方式
Python执行JS代码的三种方式;
1
使用 js2py
基本操作示例:
import js2py<br /><br /># 执行单行js语句js2py.eval_js("console.log(abcd)")>>> abcd<br /># 执行js函数add = js2py.eval_js("function add(a, b) {return a + b};")print(add(1,2))>>> 3<br /># 另一种方式js = js2py.EvalJs({})js.execute("js语句")
在js代码中引入python对象或python代码
# 在js代码中引入python对象context = js2py.EvalJs({'python_sum': sum})context.eval('python_sum(new Array(1,4,2,7))')>>> 14<br /># 在js代码中加入python代码js_code = ''' var a = 10 function f(x) {return x*x}'''context.execute(js_code)context.f("14") 或 context.f(14)>>> 196
将js代码转为python模块,再使用import 导入
# 转换js文件js2py.translate_file('example.js', 'example.py')<br /># 现在可以导入example.pyfrom example import exampleexample.someFunction()<br /><br /><br /># 转换js代码js2py.translate_js('var $ = 5')>>> """from js2py.pyjs import *# setting scopevar = Scope( JS_BUILTINS )set_global_object(var)# Code follows:var.registers(['$'])var.put('$', Js(5.0))"""
不过py2js有时候在加载一些加密函数的时候效率低的可怜,大概是因为执行
机制的不同;
py2js直接调用的nodejs引擎不过这个库用的nodejs解析语法树转成py代码,性能挺低的,还不如直接用execjs调nodejs或自己封装子进程调用。
2
使用 execjs
import execjs<br />js_code = open('file.js',encoding='utf-8').read()ctx = execjs.compile(js_code)<br /># 第一个参数为ja代码中的函数名, 后面为函数对应的参数result = ctx.call('function_name', *args)
3
使用subprocess调用node子进程
import subprocess<br /># js文件最后必须有输出,我使用的是 console.logpro = subprocess.run("node abc.js", stdout=subprocess.PIPE)# 获得标准输出_token = pro.stdout# 转一下格式token = _token.decode().strip()
3 JS动态网页抓取方式
许多时候爬虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。
一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的;
下面两种方案,可用来python爬取js执行后输出的信息。
① 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。
WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含js等的网页。
import dryscrape # 使用dryscrape库 动态抓取页面 def get_url_dynamic(url): session_req=dryscrape.Session() session_req.visit(url) #请求页面 response=session_req.body() #网页的文本 #print(response) return response get_text_line(get_url_dynamic(url)) #将输出一条文本
这里对于其余包含js的网页也是适用的,虽然可以满足抓取动态页面的要求,
但缺点还是很明显的:慢!
但想想也合理,python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回,慢一点情理之中。
除外还有很多库可以调用 webkit:PythonWebkit,PyWebKitGit,Pygt(可以用它写个浏览器),pyjamas等等,也可以实现相同的功能。
② selenium web测试框架
selenium是一个web测试框架,允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
使用 selenium webdriver 可行,但会实时打开浏览器窗口。
def get_url_dynamic2(url): driver=webdriver.Firefox() #调用本地的火狐浏览器,Chrom 甚至 Ie 也可以的 driver.get(url) #请求页面,会打开一个浏览器窗口 html_text=driver.page_source driver.quit() #print html_text return html_text get_text_line(get_url_dynamic2(url)) #将输出一条文本
不失为一条临时的解决方案,与selenium类似的框架还有一个windmill,
感觉稍复杂一些,这里就暂且不赘述了。
4解析JS
我们爬虫每次只有一个请求,但是实际上很多请求又js连带发送,所以我们需要利用爬虫解析js去实现这些请求的发送。
网页中的参数来源主要有以下四种:
这里主要介绍一下解析js,破解加密方法或者生成参数值方法,python代码模拟实现这个方法, 从而得到我们需要的请求参数。
以微博登录为例:
当我们点击登录的时候都会发送一个login请求
登录表单中的参数并不一定都是我们需要的,可以通过对比多次请求中的参数,再加上一些经验和猜想,过滤掉固定参数或服务器自带参数和用户输入的参数。
这是剩下的就是js生成的数值或加密数值;
最终得到的值:
# 图片 picture id:pcid: yf-d0efa944bb243bddcf11906cda5a46dee9b8# 用户名:su: cXdlcnRxd3Jlnonce: 2SSH2A # 未知# 密码:sp: e121946ac9273faf9c63bc0fdc5d1f84e563a4064af16f635000e49cbb2976d73734b0a8c65a6537e2e728cd123e6a34a7723c940dd2aea902fb9e7c6196e3a15ec52607fd02d5e5a28e18254105358e897996f0b9057afe2d24b491bb12ba29db3265aef533c1b57905bf02c0cee0c546f4294b0cf73a553aa1f7faf9f835e5prelt: 148 # 未知
请求参数中的用户名和密码都是经过加密处理的,如果需要模拟登录,就需要找到这个加密的方法,利用它来为我们的数据进行加密。
1)找到所需的js
要找到加密方法,首先我们需要先找到登录所需的js代码,可以使用以下3种方式:
① 找事件;在页面检查目标元素,在开发工具的子窗口里选中Events Listeners, 找到click事件,点击定位到js代码。
② 找请求;在Network中点击列表界面的对应Initiator跳转至对应js界面;
③ 通过搜索参数名进行定位;
2)登录的js代码
3)在这个submit的方法上打断点
然后输入用户名密码,先不点登录,回到dev tool点击这个按钮启用调试。
4)然后再去点登录按钮, 这时候就可以开始调试;
5)逐步执行代码的同时观察我们输入的参数, 发生变化的地方即为加密方法
如下示例:
6)上图中的加密方式是base64, 我们可以使用代码来试一下
import base64<br />a = "aaaaaaaaaaaa" # 输入的用户名print(base64.b64encode(a.encode())) # 得到的加密结果:b'YWFhYWFhYWFhYWFh'# 如果用户名包含@等特殊符号, 需要先用parse.quote()进行转义
得到的加密结果与网页上js的执行结果一致;
5爬虫中JS反爬技术
爬虫中遇到的js反爬技术(重点)
0 1
JS写cookie
requests请求得到的网页是一对JS,跟浏览器打开看到的网页源码完全不一样。
这种情况,往往是浏览器运行这段JS生成一个(或多个)cookie再带着这个cookie做二次请求。
在浏览器(chrome、Firefox都可以)里可以看到这一过程,首先把Chrome浏览器保存的该网站的cookie删除。
按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。
第一次打开“index.html”页面时返回的是521, 内容是一段JS代码;
第二次请求这个页面就得到了正常的HTML,查看两次请求的cookies,可以发现第二次请求时带上了一个cookie,而这个cookie并不是第一次请求时服务器发过来的,其实它就是JS生成的。
解决思路:研究那段JS,找到它生成cookie的算法,爬虫就可以解决这个问题。
0 2
JS加密ajax请求参数
抓某个网页里面的数据,发现网页源代码里面没有我们要的数据,麻烦之处在于数据往往是ajax请求得到的。
按F12打开Network窗口,刷新网页看看加载这个网页都下载了哪些URL,我们要的数据就在某个URL请求的结果里面。
这类URL在Chrome的Network里面的类型大多是XHR,通过观察它们的“Response”就可以发现我们要的数据。
我们可以把这个URL拷贝到地址栏,把那个参数随便改个字母,访问一下看看是不是能得到正确的结果,由此来验证它是否是很重要的加密参数。
解决思路:对于这样的加密参数,可以尝试通过debug JS来找到对应的JS加密算法,其中关键的是在Chrome里面设置“XHR/fetch Breakpoints”。
0 3
JS反调试(反debug)
前面我们都用到了Chrome 的F12去查看网页加载的过程,或者是调试JS的运行过程。
不过这种方法用多了,网站就加了反调试的策略,只有我们打开F12,就会暂停在一个“debugger”代码行,无论怎样都跳不出去。
不管我们点击多少次继续运行,它一直在这个“debugger”这里,每次都会多出一个VMxx的标签,观察“Call Stack”发现它好像陷入了一个函数的递归调用。
这个“debugger”让我们无法调试JS,但是关掉F12窗口,网页就正常加载了。
解决思路:“反-反调试”,通过“Call Stack”找到把我们带入死循环的函数,重新定义它。
JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。
0 4
JS发送鼠标点击事件
有些网站它的反爬都不是上面的方式,你从浏览器可以打开正常的页面,而在requests里面却被要求输入验证码或重定向其它网页。
可以试着从“Network”看看,比如下面这个Network流里面的信息:
认真看看后会发现,每点击页面的的链接,它都会做一个“cl.gif”的请求,它看上去是下载一个gif图片,然而并不是。
它请求时发送的参数非常多,而且这些参数都是当前页面的信息。比如包含了被点击的链接等等。
先来顺一下它的逻辑:
① JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。
② 服务器收到被点击链接的请求,会看看之前是不是已经通过cl.gif把对应信息发过来,如果发过来了就认为是合法的浏览器访问,给出正常的网页内容。
③ 因为requests没有鼠标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
解决思路:在访问链接前先访问一下cl.gif即可,关键是要研究cl.gif后的参数,把这些参数都带上问题就不大了,这样就可以绕过这个反爬策略。
END
最后:
欢迎关注「Python新手快速入门」
每天5分钟,学习一个Python小Tip!助力你成为更优秀的Python学习者~ 查看全部
动态网页抓不了?JavaScript入门攻略已发送~
var carname="Volvo";
0 3
变量命名的规则
① 由字母、数字、下划线和 $ 组成,但是不能以数字开头,如:12asd 这个名字就会报错
② 不能是关键字或保留字,比如 var、for等
③ 严格区分大小写,就是说大写和小写都是不一样的变量
0 4
数据类型
JavaScript 的数据类型分两种,一种是简单数据类型,另一种是复杂数据类型。
示例:返回的类型是一个number;
<br /> var a = 123; //var是设置一个变量 alert('hello') //一个弹窗,可以判断是否为外部引入的 console.log(a) //console.log():是在浏览器的控制台上的输出 console.log(typeof a); //typeof 判断是属于什么类型<br />
需要注意:要严格区分大小写,否则便会出现报错。
0 5
介绍几个函数
(1)Number() 将数据转换成number类型,里面的参数便是你要转变类型的数据。<br />(2)toString() String() 两种方法将数据转换成字符串类型;区别String() 可以将null 转换成"null" toString() 返回的是undefined;<br />(3)Boolean() 将数据类型转换换成布尔类型;bool 返回两种数据类型,一个是true 一个是false。在将 Boolean 类型转 Number 时,true会转为 1, false 会转为 0,这个方法不支持将数字开头带有其它字符的字符串转为数值类型,如 “12df”。
2 Python执行JS代码的方式
Python执行JS代码的三种方式;
1
使用 js2py
基本操作示例:
import js2py<br /><br /># 执行单行js语句js2py.eval_js("console.log(abcd)")>>> abcd<br /># 执行js函数add = js2py.eval_js("function add(a, b) {return a + b};")print(add(1,2))>>> 3<br /># 另一种方式js = js2py.EvalJs({})js.execute("js语句")
在js代码中引入python对象或python代码
# 在js代码中引入python对象context = js2py.EvalJs({'python_sum': sum})context.eval('python_sum(new Array(1,4,2,7))')>>> 14<br /># 在js代码中加入python代码js_code = ''' var a = 10 function f(x) {return x*x}'''context.execute(js_code)context.f("14") 或 context.f(14)>>> 196
将js代码转为python模块,再使用import 导入
# 转换js文件js2py.translate_file('example.js', 'example.py')<br /># 现在可以导入example.pyfrom example import exampleexample.someFunction()<br /><br /><br /># 转换js代码js2py.translate_js('var $ = 5')>>> """from js2py.pyjs import *# setting scopevar = Scope( JS_BUILTINS )set_global_object(var)# Code follows:var.registers(['$'])var.put('$', Js(5.0))"""
不过py2js有时候在加载一些加密函数的时候效率低的可怜,大概是因为执行
机制的不同;
py2js直接调用的nodejs引擎不过这个库用的nodejs解析语法树转成py代码,性能挺低的,还不如直接用execjs调nodejs或自己封装子进程调用。
2
使用 execjs
import execjs<br />js_code = open('file.js',encoding='utf-8').read()ctx = execjs.compile(js_code)<br /># 第一个参数为ja代码中的函数名, 后面为函数对应的参数result = ctx.call('function_name', *args)
3
使用subprocess调用node子进程
import subprocess<br /># js文件最后必须有输出,我使用的是 console.logpro = subprocess.run("node abc.js", stdout=subprocess.PIPE)# 获得标准输出_token = pro.stdout# 转一下格式token = _token.decode().strip()
3 JS动态网页抓取方式
许多时候爬虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。
一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的;
下面两种方案,可用来python爬取js执行后输出的信息。
① 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。
WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含js等的网页。
import dryscrape # 使用dryscrape库 动态抓取页面 def get_url_dynamic(url): session_req=dryscrape.Session() session_req.visit(url) #请求页面 response=session_req.body() #网页的文本 #print(response) return response get_text_line(get_url_dynamic(url)) #将输出一条文本
这里对于其余包含js的网页也是适用的,虽然可以满足抓取动态页面的要求,
但缺点还是很明显的:慢!
但想想也合理,python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回,慢一点情理之中。
除外还有很多库可以调用 webkit:PythonWebkit,PyWebKitGit,Pygt(可以用它写个浏览器),pyjamas等等,也可以实现相同的功能。
② selenium web测试框架
selenium是一个web测试框架,允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
使用 selenium webdriver 可行,但会实时打开浏览器窗口。
def get_url_dynamic2(url): driver=webdriver.Firefox() #调用本地的火狐浏览器,Chrom 甚至 Ie 也可以的 driver.get(url) #请求页面,会打开一个浏览器窗口 html_text=driver.page_source driver.quit() #print html_text return html_text get_text_line(get_url_dynamic2(url)) #将输出一条文本
不失为一条临时的解决方案,与selenium类似的框架还有一个windmill,
感觉稍复杂一些,这里就暂且不赘述了。
4解析JS
我们爬虫每次只有一个请求,但是实际上很多请求又js连带发送,所以我们需要利用爬虫解析js去实现这些请求的发送。
网页中的参数来源主要有以下四种:
这里主要介绍一下解析js,破解加密方法或者生成参数值方法,python代码模拟实现这个方法, 从而得到我们需要的请求参数。
以微博登录为例:
当我们点击登录的时候都会发送一个login请求
登录表单中的参数并不一定都是我们需要的,可以通过对比多次请求中的参数,再加上一些经验和猜想,过滤掉固定参数或服务器自带参数和用户输入的参数。
这是剩下的就是js生成的数值或加密数值;
最终得到的值:
# 图片 picture id:pcid: yf-d0efa944bb243bddcf11906cda5a46dee9b8# 用户名:su: cXdlcnRxd3Jlnonce: 2SSH2A # 未知# 密码:sp: e121946ac9273faf9c63bc0fdc5d1f84e563a4064af16f635000e49cbb2976d73734b0a8c65a6537e2e728cd123e6a34a7723c940dd2aea902fb9e7c6196e3a15ec52607fd02d5e5a28e18254105358e897996f0b9057afe2d24b491bb12ba29db3265aef533c1b57905bf02c0cee0c546f4294b0cf73a553aa1f7faf9f835e5prelt: 148 # 未知
请求参数中的用户名和密码都是经过加密处理的,如果需要模拟登录,就需要找到这个加密的方法,利用它来为我们的数据进行加密。
1)找到所需的js
要找到加密方法,首先我们需要先找到登录所需的js代码,可以使用以下3种方式:
① 找事件;在页面检查目标元素,在开发工具的子窗口里选中Events Listeners, 找到click事件,点击定位到js代码。
② 找请求;在Network中点击列表界面的对应Initiator跳转至对应js界面;
③ 通过搜索参数名进行定位;
2)登录的js代码
3)在这个submit的方法上打断点
然后输入用户名密码,先不点登录,回到dev tool点击这个按钮启用调试。
4)然后再去点登录按钮, 这时候就可以开始调试;
5)逐步执行代码的同时观察我们输入的参数, 发生变化的地方即为加密方法
如下示例:
6)上图中的加密方式是base64, 我们可以使用代码来试一下
import base64<br />a = "aaaaaaaaaaaa" # 输入的用户名print(base64.b64encode(a.encode())) # 得到的加密结果:b'YWFhYWFhYWFhYWFh'# 如果用户名包含@等特殊符号, 需要先用parse.quote()进行转义
得到的加密结果与网页上js的执行结果一致;
5爬虫中JS反爬技术
爬虫中遇到的js反爬技术(重点)
0 1
JS写cookie
requests请求得到的网页是一对JS,跟浏览器打开看到的网页源码完全不一样。
这种情况,往往是浏览器运行这段JS生成一个(或多个)cookie再带着这个cookie做二次请求。
在浏览器(chrome、Firefox都可以)里可以看到这一过程,首先把Chrome浏览器保存的该网站的cookie删除。
按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。
第一次打开“index.html”页面时返回的是521, 内容是一段JS代码;
第二次请求这个页面就得到了正常的HTML,查看两次请求的cookies,可以发现第二次请求时带上了一个cookie,而这个cookie并不是第一次请求时服务器发过来的,其实它就是JS生成的。
解决思路:研究那段JS,找到它生成cookie的算法,爬虫就可以解决这个问题。
0 2
JS加密ajax请求参数
抓某个网页里面的数据,发现网页源代码里面没有我们要的数据,麻烦之处在于数据往往是ajax请求得到的。
按F12打开Network窗口,刷新网页看看加载这个网页都下载了哪些URL,我们要的数据就在某个URL请求的结果里面。
这类URL在Chrome的Network里面的类型大多是XHR,通过观察它们的“Response”就可以发现我们要的数据。
我们可以把这个URL拷贝到地址栏,把那个参数随便改个字母,访问一下看看是不是能得到正确的结果,由此来验证它是否是很重要的加密参数。
解决思路:对于这样的加密参数,可以尝试通过debug JS来找到对应的JS加密算法,其中关键的是在Chrome里面设置“XHR/fetch Breakpoints”。
0 3
JS反调试(反debug)
前面我们都用到了Chrome 的F12去查看网页加载的过程,或者是调试JS的运行过程。
不过这种方法用多了,网站就加了反调试的策略,只有我们打开F12,就会暂停在一个“debugger”代码行,无论怎样都跳不出去。
不管我们点击多少次继续运行,它一直在这个“debugger”这里,每次都会多出一个VMxx的标签,观察“Call Stack”发现它好像陷入了一个函数的递归调用。
这个“debugger”让我们无法调试JS,但是关掉F12窗口,网页就正常加载了。
解决思路:“反-反调试”,通过“Call Stack”找到把我们带入死循环的函数,重新定义它。
JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。
0 4
JS发送鼠标点击事件
有些网站它的反爬都不是上面的方式,你从浏览器可以打开正常的页面,而在requests里面却被要求输入验证码或重定向其它网页。
可以试着从“Network”看看,比如下面这个Network流里面的信息:
认真看看后会发现,每点击页面的的链接,它都会做一个“cl.gif”的请求,它看上去是下载一个gif图片,然而并不是。
它请求时发送的参数非常多,而且这些参数都是当前页面的信息。比如包含了被点击的链接等等。
先来顺一下它的逻辑:
① JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。
② 服务器收到被点击链接的请求,会看看之前是不是已经通过cl.gif把对应信息发过来,如果发过来了就认为是合法的浏览器访问,给出正常的网页内容。
③ 因为requests没有鼠标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
解决思路:在访问链接前先访问一下cl.gif即可,关键是要研究cl.gif后的参数,把这些参数都带上问题就不大了,这样就可以绕过这个反爬策略。
END
最后:
欢迎关注「Python新手快速入门」
每天5分钟,学习一个Python小Tip!助力你成为更优秀的Python学习者~
javascriptscrapy工具来抓取网页内容的解决办法(一)——ajax抓取
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-06-06 20:01
ajax抓取网页内容是一个非常经典的技术,解决的问题也非常的广泛。开发一个工具来抓取站点的内容,不仅速度快,还能去除站点上的广告数据,对于抓取用户体验来说非常好。而且,如果抓取的速度不够快,那么这个工具在服务器上就要多连接几次,这种情况就会带来性能问题。因此有大神发明了javascriptscrapy工具来抓取网页内容,那么这个javascriptscrapy工具具体是干嘛的呢?今天我就给大家演示一下。
安装javascriptscrapy工具直接复制官方地址:-scrapy/scrapy-docs就可以直接进行安装。但是这样会出现一个问题,网站使用正则表达式处理,因此ip限制是必须要写在配置文件的。解决办法在配置文件中直接添加这条路径,可以满足80%的要求。此外,利用正则表达式还可以处理一些中文文本。
特别的是,javascript在python中也能使用,但是使用起来会有点吃力。我们可以通过如下方式来解决python和javascript中文处理的问题。解决办法目前最好的是使用python来处理,因为javascript提供了正则表达式api,并且在正则表达式的参数中写入python代码,就可以调用正则表达式了。
这里建议大家考虑使用python2的正则表达式库genesis-enhance-re,但是,这个库的中文处理速度慢,需要自己进行编译。不过相信日后genesis-enhance-re会与python3版本兼容,性能会有所提升。我们实际上是抓取一条ajax文本内容,在抓取结束的时候返回json格式数据。
如果速度够快,可以将字符串拼接方式切分一下,然后保存到本地。ajax抓取需要下载python,pip要安装,所以可以运行如下命令安装:pip3installjson_format-python-win32-pip6#pipinstallformat2-python-win32-pip6#pipinstallpython-win32-pip6default_as_pythonx.py,它会自动把python代码和json转换成json文件:pythonformat2.py>json_format.json编译json文件:pythonpython./python./json_format.json提取python中的所有对象:pythonobj_dict.py>json_format.json如果需要用python的doc编写正则表达式,可以通过正则表达式形式和参数形式一起来抓取,这里在编译的时候在python.py脚本的末尾添加了这样的正则表达式形式的代码:importreconst_value='{"disable_format":false,"comments":["","","",""],"overwrite":true}'有了这些特性,利用正则表达式不仅能轻松抓取网。 查看全部
javascriptscrapy工具来抓取网页内容的解决办法(一)——ajax抓取
ajax抓取网页内容是一个非常经典的技术,解决的问题也非常的广泛。开发一个工具来抓取站点的内容,不仅速度快,还能去除站点上的广告数据,对于抓取用户体验来说非常好。而且,如果抓取的速度不够快,那么这个工具在服务器上就要多连接几次,这种情况就会带来性能问题。因此有大神发明了javascriptscrapy工具来抓取网页内容,那么这个javascriptscrapy工具具体是干嘛的呢?今天我就给大家演示一下。
安装javascriptscrapy工具直接复制官方地址:-scrapy/scrapy-docs就可以直接进行安装。但是这样会出现一个问题,网站使用正则表达式处理,因此ip限制是必须要写在配置文件的。解决办法在配置文件中直接添加这条路径,可以满足80%的要求。此外,利用正则表达式还可以处理一些中文文本。
特别的是,javascript在python中也能使用,但是使用起来会有点吃力。我们可以通过如下方式来解决python和javascript中文处理的问题。解决办法目前最好的是使用python来处理,因为javascript提供了正则表达式api,并且在正则表达式的参数中写入python代码,就可以调用正则表达式了。
这里建议大家考虑使用python2的正则表达式库genesis-enhance-re,但是,这个库的中文处理速度慢,需要自己进行编译。不过相信日后genesis-enhance-re会与python3版本兼容,性能会有所提升。我们实际上是抓取一条ajax文本内容,在抓取结束的时候返回json格式数据。
如果速度够快,可以将字符串拼接方式切分一下,然后保存到本地。ajax抓取需要下载python,pip要安装,所以可以运行如下命令安装:pip3installjson_format-python-win32-pip6#pipinstallformat2-python-win32-pip6#pipinstallpython-win32-pip6default_as_pythonx.py,它会自动把python代码和json转换成json文件:pythonformat2.py>json_format.json编译json文件:pythonpython./python./json_format.json提取python中的所有对象:pythonobj_dict.py>json_format.json如果需要用python的doc编写正则表达式,可以通过正则表达式形式和参数形式一起来抓取,这里在编译的时候在python.py脚本的末尾添加了这样的正则表达式形式的代码:importreconst_value='{"disable_format":false,"comments":["","","",""],"overwrite":true}'有了这些特性,利用正则表达式不仅能轻松抓取网。
ajax解析最基础的方法是使用起来太麻烦,三步完成
网站优化 • 优采云 发表了文章 • 0 个评论 • 90 次浏览 • 2022-05-31 19:02
ajax抓取网页内容,这种技术已经应用于大量的项目中,但依然存在很多局限性。这些局限性,就是使用起来太麻烦。如果用简单的方法,可以三步完成抓取。ajax抓取效率太低目前的ajax技术,还无法把页面中所有内容完全抓取下来。有一些可以达到完全抓取的效果,但其实还不够完美。比如最近我在做的一个项目。会定期做一些数据的补充,以及增加一些普通方法无法抓取到的网页内容。
效率太低,那就降低要求,使用最基础的方法也能达到完整抓取。ajax抓取长链接容易导致页面被劫持当页面内容存在于网络中时,往往会以很多小块数据来存储。常见的就是转发,多条链接用一个url,其中转发的url长度不超过页面宽度(这里就需要用一些解析库解析长链接了)。那么有可能一个页面中会存在几十甚至上百条转发数据。
如果把所有的数据全部抓取下来,就会导致页面被刷新,页面中的所有数据全部被覆盖了。这无论是对于爬虫来说,还是对于我们来说,都不是一个好的爬虫方案。这种方法抓取的数据会有一定的局限性,比如:①数据抓取的结果有可能出现被泄露②时常可能存在页面被劫持的情况③静态资源在抓取的同时可能也会被读取③静态资源有时候会被加密,保存在自己服务器上,可能会被劫持要实现完整抓取,在手头又没有强大的开发工具支持时,只能考虑自己动手实现了。
ajax解析最基础的方法就是使用正则表达式对网页进行扫描。正则表达式可以解析的内容实在太多,这里我会简单介绍一下ajax常用的正则表达式:正则表达式={a:{c:1,d:3}}\d{2,4}\d{3,5}\d{4,5}\d{5,6}\d{6,8}\d{7,9}\d{10,11}\d{12,12}\d{13,14}然后是元素的name或tagname的匹配,包括每个元素的属性元素,name下属元素的属性,tagname下属元素的属性等。
在使用正则表达式匹配的同时,每一个元素下的属性也要一并匹配到。以上分析的是每个元素下的属性,那么像每个元素分类别的内容怎么办呢?这就要借助javascript解析javascript语法。像这样的一些文字,有些可以用let()方法定义为变量,有些可以用var()定义成函数。没有let()方法,可以用var()方法;有var()方法,可以用let()方法,但是推荐使用let()方法。
正则表达式常用的匹配方法:正则表达式匹配语法这些匹配方法的目的很明确,就是为了确定元素下的所有属性。他们很相似,但是还是有差别。不过一旦掌握了上面的方法,这些区别就可以不用关心了。let()方法最常用于匹配某个元素的属性,比如。 查看全部
ajax解析最基础的方法是使用起来太麻烦,三步完成
ajax抓取网页内容,这种技术已经应用于大量的项目中,但依然存在很多局限性。这些局限性,就是使用起来太麻烦。如果用简单的方法,可以三步完成抓取。ajax抓取效率太低目前的ajax技术,还无法把页面中所有内容完全抓取下来。有一些可以达到完全抓取的效果,但其实还不够完美。比如最近我在做的一个项目。会定期做一些数据的补充,以及增加一些普通方法无法抓取到的网页内容。
效率太低,那就降低要求,使用最基础的方法也能达到完整抓取。ajax抓取长链接容易导致页面被劫持当页面内容存在于网络中时,往往会以很多小块数据来存储。常见的就是转发,多条链接用一个url,其中转发的url长度不超过页面宽度(这里就需要用一些解析库解析长链接了)。那么有可能一个页面中会存在几十甚至上百条转发数据。
如果把所有的数据全部抓取下来,就会导致页面被刷新,页面中的所有数据全部被覆盖了。这无论是对于爬虫来说,还是对于我们来说,都不是一个好的爬虫方案。这种方法抓取的数据会有一定的局限性,比如:①数据抓取的结果有可能出现被泄露②时常可能存在页面被劫持的情况③静态资源在抓取的同时可能也会被读取③静态资源有时候会被加密,保存在自己服务器上,可能会被劫持要实现完整抓取,在手头又没有强大的开发工具支持时,只能考虑自己动手实现了。
ajax解析最基础的方法就是使用正则表达式对网页进行扫描。正则表达式可以解析的内容实在太多,这里我会简单介绍一下ajax常用的正则表达式:正则表达式={a:{c:1,d:3}}\d{2,4}\d{3,5}\d{4,5}\d{5,6}\d{6,8}\d{7,9}\d{10,11}\d{12,12}\d{13,14}然后是元素的name或tagname的匹配,包括每个元素的属性元素,name下属元素的属性,tagname下属元素的属性等。
在使用正则表达式匹配的同时,每一个元素下的属性也要一并匹配到。以上分析的是每个元素下的属性,那么像每个元素分类别的内容怎么办呢?这就要借助javascript解析javascript语法。像这样的一些文字,有些可以用let()方法定义为变量,有些可以用var()定义成函数。没有let()方法,可以用var()方法;有var()方法,可以用let()方法,但是推荐使用let()方法。
正则表达式常用的匹配方法:正则表达式匹配语法这些匹配方法的目的很明确,就是为了确定元素下的所有属性。他们很相似,但是还是有差别。不过一旦掌握了上面的方法,这些区别就可以不用关心了。let()方法最常用于匹配某个元素的属性,比如。
Python数据抓取(1) —数据处理前的准备
网站优化 • 优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-05-23 23:19
(一)数据抓取概要
如何将非结构化的数据转化为结构化的数据呢?
(二)抓取的逻辑—ETL
ETL是什么?
(三)数据抓取前的准备1.“网络爬虫”架构
网络爬虫构架
2、如何理解“网络爬虫”架构
对量化投资策略进行研究,第一步就是获取我们需要的数据,在工作实践中,比较实用的数据源就是新浪财经的数据,下面我们以新浪财经为例,为大家梳理下网络爬虫的构架
3、以抓取一个网页的内容为目的,如何去观察一个网页
我们有新浪财经的股票博客信息,我们该如何把这些信息,包含标题和时间抓取出来?
(1)使用开发人员工具观察
(2)观察Requests的构成
通常来讲,文章和新闻会放在Doc下,接下来我们要抓取的链接就藏在106个链接中的某个链接; 查看全部
Python数据抓取(1) —数据处理前的准备
(一)数据抓取概要
如何将非结构化的数据转化为结构化的数据呢?
(二)抓取的逻辑—ETL
ETL是什么?
(三)数据抓取前的准备1.“网络爬虫”架构
网络爬虫构架
2、如何理解“网络爬虫”架构
对量化投资策略进行研究,第一步就是获取我们需要的数据,在工作实践中,比较实用的数据源就是新浪财经的数据,下面我们以新浪财经为例,为大家梳理下网络爬虫的构架
3、以抓取一个网页的内容为目的,如何去观察一个网页
我们有新浪财经的股票博客信息,我们该如何把这些信息,包含标题和时间抓取出来?
(1)使用开发人员工具观察
(2)观察Requests的构成
通常来讲,文章和新闻会放在Doc下,接下来我们要抓取的链接就藏在106个链接中的某个链接;
springboot案例实战手写高效率ajax应用开发。(图)
网站优化 • 优采云 发表了文章 • 0 个评论 • 71 次浏览 • 2022-05-18 06:00
ajax抓取网页内容。首先需要明确一个问题,ajax本身并不是一个技术。只不过ajax能够让网页实现动态更新。那么我们抓取网页内容时,通常会使用一些相关技术,比如flashjavascriptjavascript,cookie等等。具体可以参考如下帖子。springboot案例实战手写高效率ajax应用开发。
一般来说抓取网页源代码一般是先抓取html源代码,再抓取js和css文件。ajax可以让服务器在一个应用内同时处理请求和更新,比如动态加载、刷新等。
我用的是activex标签。把上面图片提取出来。然后发送到postman调用处理。
一、ajax不是应用技术,而是指一种xmlhttprequest对象的特性:异步(同步请求失败后即返回非null)、无连接(在请求和响应过程中都没有包含任何连接)、幂等(在请求和响应过程中,不重复发送和接收数据),幂等是ajax的重要特性,它可以将xml数据从一个主线程传送到另一个主线程。这是ajax的核心思想,值得注意的是ajax使用的非常广泛,尤其是java、php、python等语言。
因此ajax是运用范围最广的一种应用技术。ajax相比于传统的http请求,ajax是一种应用层的技术,它在接收到响应结果的时候,已经不需要再加载其他的页面内容。大多数用php写的服务器端代码,可以把php的ajax方法封装在内置对象中供内置浏览器使用,比如preljs,同时还可以传递参数,比如request.xmlhttprequest(),request.xmlcrypt(),这样的技术就叫做定制ajax,比如postman,也可以按需定制ajax方法,例如springactivex,qqactivex接口等等。
二、ajax模式的两种实现方式:ajax本质上是通过javascript作为服务器传递数据的方式,首先创建xmlhttprequest对象,然后利用xmlhttprequest对象实现http请求,一般传递数据的话,都是传递带有token的数据,如果token不明确,就用accept-to-string解决,也就是服务器自己去请求数据,很多情况下,网页代码都是使用xmlhttprequest对象去渲染,因此服务器端都会提供额外的方法,也就是jsonp协议,在jsonp协议中,参数或者跳转的数据是不会返回到浏览器的,而是直接解析数据,然后再发送给浏览器,可以理解为post请求,但是http协议规定是只能以tcp方式连接,所以只能通过socket协议传输,即tcp。
首先注意一点,用于连接数据的ajax请求不存在浏览器回调方法,其实这个协议理论上只有一个post请求,主要是w3c一直不建议使用浏览器中的回调机制。而用于接收数据的则有cookie和urlstring方法。 查看全部
springboot案例实战手写高效率ajax应用开发。(图)
ajax抓取网页内容。首先需要明确一个问题,ajax本身并不是一个技术。只不过ajax能够让网页实现动态更新。那么我们抓取网页内容时,通常会使用一些相关技术,比如flashjavascriptjavascript,cookie等等。具体可以参考如下帖子。springboot案例实战手写高效率ajax应用开发。
一般来说抓取网页源代码一般是先抓取html源代码,再抓取js和css文件。ajax可以让服务器在一个应用内同时处理请求和更新,比如动态加载、刷新等。
我用的是activex标签。把上面图片提取出来。然后发送到postman调用处理。
一、ajax不是应用技术,而是指一种xmlhttprequest对象的特性:异步(同步请求失败后即返回非null)、无连接(在请求和响应过程中都没有包含任何连接)、幂等(在请求和响应过程中,不重复发送和接收数据),幂等是ajax的重要特性,它可以将xml数据从一个主线程传送到另一个主线程。这是ajax的核心思想,值得注意的是ajax使用的非常广泛,尤其是java、php、python等语言。
因此ajax是运用范围最广的一种应用技术。ajax相比于传统的http请求,ajax是一种应用层的技术,它在接收到响应结果的时候,已经不需要再加载其他的页面内容。大多数用php写的服务器端代码,可以把php的ajax方法封装在内置对象中供内置浏览器使用,比如preljs,同时还可以传递参数,比如request.xmlhttprequest(),request.xmlcrypt(),这样的技术就叫做定制ajax,比如postman,也可以按需定制ajax方法,例如springactivex,qqactivex接口等等。
二、ajax模式的两种实现方式:ajax本质上是通过javascript作为服务器传递数据的方式,首先创建xmlhttprequest对象,然后利用xmlhttprequest对象实现http请求,一般传递数据的话,都是传递带有token的数据,如果token不明确,就用accept-to-string解决,也就是服务器自己去请求数据,很多情况下,网页代码都是使用xmlhttprequest对象去渲染,因此服务器端都会提供额外的方法,也就是jsonp协议,在jsonp协议中,参数或者跳转的数据是不会返回到浏览器的,而是直接解析数据,然后再发送给浏览器,可以理解为post请求,但是http协议规定是只能以tcp方式连接,所以只能通过socket协议传输,即tcp。
首先注意一点,用于连接数据的ajax请求不存在浏览器回调方法,其实这个协议理论上只有一个post请求,主要是w3c一直不建议使用浏览器中的回调机制。而用于接收数据的则有cookie和urlstring方法。
百度收录网站的要求是什么?
网站优化 • 优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-05-08 23:18
做好网站排名之前最为关键的因素就是解决网站的收录问题。针对百度,它占据了绝大的搜索引擎市场份额,可谓说一家独大。那百度收录网站的要求是什么呢?
提到百度收录的网站的要求,最开始我不得不说的就是搜索引擎爬虫的抓取。如果搜索引擎爬虫不能抓取你的网站,或者爬虫无法识别网页内容的话,那百度几乎不会收录你的网站了。
爬虫抓取的可识别性
在爬虫抓取网页时,如果根本不知道你的网页内容是什么,那基本上是不会被百度收录的。所以让爬虫识别到我们网页的内容也是较为关键的一个问题。
1、robots协议的封禁
robots是一个txt文件,放置于网站的根目录下。可以通过进行访问打开。如果你的robots文件封禁了百度爬虫,那么收录简直是不可能的。
因为robots协议文件是搜索引擎与网站之间的协议文件。是网站告知搜索引擎爬虫,哪些内容你可以抓取,哪些内容你是不可以抓取。所以你都告诉爬虫不让它抓取了,他还怎么会抓取呢?
2、影响网站收录的ajax技术
js的ajax技术,其实很多做SEO的都知道不能使用js,但这并不完全是。因为爬虫抓取的是网页源代码,只要你源代码中有这些内容就是可以的。但通过js实现异步加载的内容就不行了。
这里解释一下什么是异步加载,就是当前网页源代码没有的内容。通过触发网页某个事件,js通过ajax技术动态加载出来的内容。例如典型的瀑布流网页,当你鼠标滚动到最底部,然后地步就会出现更多新的内容。多数是采用这个ajax技术。
那被异步加载出来的内容爬虫是看不到的。
3、图片、导航、ALT
图片类型的导航,现在基本很少见了。但这里还是要说一下,如果你的导航(主导航)使用图片,在这个寸土寸金的位置上,搜索引擎根本不知道你说了什么,所以这时候需要我们使用alt标签进行设置。
alt严格来说是img标签的一个属性值,是在当图片加载失败时的提示文字。如下图示例:
如上图,当图片的链接是错误时,红框中出现的就是下面源代码中alt的内容。
当然了,alt属性并不单单可以应用在图片导航中。所有你认为重要的图片,都可以进行设置,并合理的融入关键词。像一些素材图片就可以不用设置alt属性了。
4、网站访问速度慢
如果你的网站打开速度很慢的话,也会很大程度上的影响收录。我们举个例子,爬虫每天抓取你网站就给10分钟时间,你的网站访问一次需要1秒钟,和需要100毫秒。这完全是两个层次上的结果。
内容质量对收录的影响 查看全部
百度收录网站的要求是什么?
做好网站排名之前最为关键的因素就是解决网站的收录问题。针对百度,它占据了绝大的搜索引擎市场份额,可谓说一家独大。那百度收录网站的要求是什么呢?
提到百度收录的网站的要求,最开始我不得不说的就是搜索引擎爬虫的抓取。如果搜索引擎爬虫不能抓取你的网站,或者爬虫无法识别网页内容的话,那百度几乎不会收录你的网站了。
爬虫抓取的可识别性
在爬虫抓取网页时,如果根本不知道你的网页内容是什么,那基本上是不会被百度收录的。所以让爬虫识别到我们网页的内容也是较为关键的一个问题。
1、robots协议的封禁
robots是一个txt文件,放置于网站的根目录下。可以通过进行访问打开。如果你的robots文件封禁了百度爬虫,那么收录简直是不可能的。
因为robots协议文件是搜索引擎与网站之间的协议文件。是网站告知搜索引擎爬虫,哪些内容你可以抓取,哪些内容你是不可以抓取。所以你都告诉爬虫不让它抓取了,他还怎么会抓取呢?
2、影响网站收录的ajax技术
js的ajax技术,其实很多做SEO的都知道不能使用js,但这并不完全是。因为爬虫抓取的是网页源代码,只要你源代码中有这些内容就是可以的。但通过js实现异步加载的内容就不行了。
这里解释一下什么是异步加载,就是当前网页源代码没有的内容。通过触发网页某个事件,js通过ajax技术动态加载出来的内容。例如典型的瀑布流网页,当你鼠标滚动到最底部,然后地步就会出现更多新的内容。多数是采用这个ajax技术。
那被异步加载出来的内容爬虫是看不到的。
3、图片、导航、ALT
图片类型的导航,现在基本很少见了。但这里还是要说一下,如果你的导航(主导航)使用图片,在这个寸土寸金的位置上,搜索引擎根本不知道你说了什么,所以这时候需要我们使用alt标签进行设置。
alt严格来说是img标签的一个属性值,是在当图片加载失败时的提示文字。如下图示例:
如上图,当图片的链接是错误时,红框中出现的就是下面源代码中alt的内容。
当然了,alt属性并不单单可以应用在图片导航中。所有你认为重要的图片,都可以进行设置,并合理的融入关键词。像一些素材图片就可以不用设置alt属性了。
4、网站访问速度慢
如果你的网站打开速度很慢的话,也会很大程度上的影响收录。我们举个例子,爬虫每天抓取你网站就给10分钟时间,你的网站访问一次需要1秒钟,和需要100毫秒。这完全是两个层次上的结果。
内容质量对收录的影响
Python入门网络爬虫之精华版
网站优化 • 优采云 发表了文章 • 0 个评论 • 89 次浏览 • 2022-05-08 23:18
来源:宁哥的小站»Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储。
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = requests.get(url).content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = urllib2.urlopen(url).read()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Httplib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import httplib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> http = httplib2.Http()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response_headers, content = http.request(url, 'GET')<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response_headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, params=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> full_url = url+'?'+data<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(full_url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.post(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import requests <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />requests_session = requests.session() <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response = requests_session.post(url=url_login, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">response_captcha = requests_session.get(url=url_login, cookies=cookies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response1 = requests.get(url_login) # 未登陆<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, proxies=proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> proxy_support = urllib2.ProxyHandler(proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import time<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />time.sleep(1)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
4. 对于断线重连
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_session(session, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return session.post(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
或者
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_open(opener, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return opener.open(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">禁止所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: BadBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: GoodBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
学习Python和网络爬虫 查看全部
Python入门网络爬虫之精华版
来源:宁哥的小站»Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储。
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = requests.get(url).content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = urllib2.urlopen(url).read()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Httplib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import httplib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> http = httplib2.Http()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response_headers, content = http.request(url, 'GET')<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response_headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, params=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> full_url = url+'?'+data<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(full_url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.post(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import requests <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />requests_session = requests.session() <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response = requests_session.post(url=url_login, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">response_captcha = requests_session.get(url=url_login, cookies=cookies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response1 = requests.get(url_login) # 未登陆<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, proxies=proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> proxy_support = urllib2.ProxyHandler(proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import time<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />time.sleep(1)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
4. 对于断线重连
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_session(session, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return session.post(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
或者
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_open(opener, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return opener.open(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">禁止所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: BadBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: GoodBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
学习Python和网络爬虫
R语言爬虫系列4|AJAX与动态网页介绍
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-05-08 02:01
作者:鲁伟,热爱数据,坚信数据技术和代码改变世界。R语言和Python的忠实拥趸,为成为一名未来的数据科学家而奋斗终生。个人公众号:数据科学家养成记 (微信ID:louwill12)
第一篇戳:
第二篇戳:
第三篇戳:
很早之前就写过用rvest包实现对静态网页的抓取之类的文章,以至于很久之后看到那些文章的朋友还拿来套,以为换个网址也能达到同样的抓取效果。然而事与愿违,殊不知这些通常自己会“动”,明明是同一个url,前后硬是两个不同的网页内容,利用rvest的爬虫自然也就失效了。
究其缘由,还是在于有些网页的HTML/HTTP基础架构在一个页面布局中静态地显示内容,但是如果你用R函数来解析知乎首页,咱能通过这个首页实现抓取目的吗?答案当然是不能的。因为知乎首页是一个动态网站(DHTML),具体表现就是从首页不断下拉,网页内容在不断变化但url却一直都是,或者是点击了某个地方内容也发生了变化但抬头一看地址栏,url依然没有变化。对这样的网页进行抓取哪能按照以前的简单套路来?明显是不可行的。
网络技术实现从静态到动态转变的一个关键角色是汇总于AJAX这个术语下的一组技术,所谓AJAX,全称叫做异步JavaScript和XML(Asynchronous JavaScript and XML),它是一组技术,不同的浏览器有自己的AJAX实现组件,有了AJAX技术之后,就不需要对整个网页进行刷新了,局部更新既不占用宽带又可以提高加载速度有没有,比如说刚刚的知乎首页,想看新内容?不断把网页下拉自动加载就好。
再举个例子:比如说你们班拍毕业照,照完之后洗出来才发现哎呀少了一个人,那怎么办呢?传统的方式就是重新把大家集合起来再拍一次,那AJAX就不会这么做了,AJAX会把这位漏掉的同学P到先前的合照中去。总之,AJAX可以在不重新加载整个网页的情况下对网页的局部进行更新的某种技术。
JavaScript如何将HTML网页转化为DHTML?
JavaScript号称最流行的Web编程脚本语言,可惜小编并不懂这门语言,但这不妨碍咱们的网络数据抓取的需要。在爬虫专栏开始的第一篇文章的时候小编就说过,HTML、CSS和JavaScript是前端技术的三驾马车,要认识原生的JavaScript,重要的是了解其对于HTML的三种改进方法:
1.以HTML中的 查看全部
R语言爬虫系列4|AJAX与动态网页介绍
作者:鲁伟,热爱数据,坚信数据技术和代码改变世界。R语言和Python的忠实拥趸,为成为一名未来的数据科学家而奋斗终生。个人公众号:数据科学家养成记 (微信ID:louwill12)
第一篇戳:
第二篇戳:
第三篇戳:
很早之前就写过用rvest包实现对静态网页的抓取之类的文章,以至于很久之后看到那些文章的朋友还拿来套,以为换个网址也能达到同样的抓取效果。然而事与愿违,殊不知这些通常自己会“动”,明明是同一个url,前后硬是两个不同的网页内容,利用rvest的爬虫自然也就失效了。
究其缘由,还是在于有些网页的HTML/HTTP基础架构在一个页面布局中静态地显示内容,但是如果你用R函数来解析知乎首页,咱能通过这个首页实现抓取目的吗?答案当然是不能的。因为知乎首页是一个动态网站(DHTML),具体表现就是从首页不断下拉,网页内容在不断变化但url却一直都是,或者是点击了某个地方内容也发生了变化但抬头一看地址栏,url依然没有变化。对这样的网页进行抓取哪能按照以前的简单套路来?明显是不可行的。
网络技术实现从静态到动态转变的一个关键角色是汇总于AJAX这个术语下的一组技术,所谓AJAX,全称叫做异步JavaScript和XML(Asynchronous JavaScript and XML),它是一组技术,不同的浏览器有自己的AJAX实现组件,有了AJAX技术之后,就不需要对整个网页进行刷新了,局部更新既不占用宽带又可以提高加载速度有没有,比如说刚刚的知乎首页,想看新内容?不断把网页下拉自动加载就好。
再举个例子:比如说你们班拍毕业照,照完之后洗出来才发现哎呀少了一个人,那怎么办呢?传统的方式就是重新把大家集合起来再拍一次,那AJAX就不会这么做了,AJAX会把这位漏掉的同学P到先前的合照中去。总之,AJAX可以在不重新加载整个网页的情况下对网页的局部进行更新的某种技术。
JavaScript如何将HTML网页转化为DHTML?
JavaScript号称最流行的Web编程脚本语言,可惜小编并不懂这门语言,但这不妨碍咱们的网络数据抓取的需要。在爬虫专栏开始的第一篇文章的时候小编就说过,HTML、CSS和JavaScript是前端技术的三驾马车,要认识原生的JavaScript,重要的是了解其对于HTML的三种改进方法:
1.以HTML中的
【免费毕设】基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+lunw
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-05-08 01:32
点击上方蓝字关注我吧!
4.2 数据库的设计
本课题包含一张用于存放抓取回来的网页信息如表1。
表1 网页数据存储表
4.3 模块设计
该模型按照功能划分为三个部分,一是爬虫抓取网页部分,二是从数据库建立索引部分,三是从前台页面查询部分。系统的功能流程(如图5.1和5.2)。
该系统用3个模块来实现搜索引擎的主要功能。流程如上图所示。
从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。这条件可以是限定的某个域名空间、或者是限定的网页抓取级数。当在获取URL时存在这样的问题就是在实际应用中主要以绝对地址和相对地址来表现。绝对地址是指一个准确的、无歧义的Internet资源的位置,包含域名(主机名)、路径名和文件名;相对地址是绝对地址的一部分。然后把抓取到的网页信息包括网页内容、标题、链接抓取时间等信息经过‘减肥’后保存到网页存储数据库表里。然后通过正则表达式,去掉多余的HTML标签。因为抓取的网页含有HTML标签、Javascript等,对搜索多余的信息,如果抓取到的网页不经过处理就会使搜索变得不够精确。
让爬虫程序能继续运行下去,就得抓取这个网页上的其它URL,所以要用正则将这个网页上的所有URL都取出来放到一个队列里。用同样的方法继续抓取网页,这里将运用到多线程技术。
为了对文档进行索引,Lucene提供了五个基础的类,他们分别是Document,Field,IndexWriter,Analyzer,Directory Document是用来描述文档的,这里的文档可以指一个HTML页面,一封电子邮件,或者是一个文本文件。一个Document对象由多个Field对象组成的。可以把一个Document对象想象成数据库中的一个记录,而每个Field对象就是记录的一个字段。在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由Analyzer来做的。Analyzer类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的Analyzer。Analyzer把分词后的内容交给IndexWriter来建立索引。
论文目录:
END
联系我
获取更多资源
学习更上一层楼 查看全部
【免费毕设】基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+lunw
点击上方蓝字关注我吧!
4.2 数据库的设计
本课题包含一张用于存放抓取回来的网页信息如表1。
表1 网页数据存储表
4.3 模块设计
该模型按照功能划分为三个部分,一是爬虫抓取网页部分,二是从数据库建立索引部分,三是从前台页面查询部分。系统的功能流程(如图5.1和5.2)。
该系统用3个模块来实现搜索引擎的主要功能。流程如上图所示。
从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。这条件可以是限定的某个域名空间、或者是限定的网页抓取级数。当在获取URL时存在这样的问题就是在实际应用中主要以绝对地址和相对地址来表现。绝对地址是指一个准确的、无歧义的Internet资源的位置,包含域名(主机名)、路径名和文件名;相对地址是绝对地址的一部分。然后把抓取到的网页信息包括网页内容、标题、链接抓取时间等信息经过‘减肥’后保存到网页存储数据库表里。然后通过正则表达式,去掉多余的HTML标签。因为抓取的网页含有HTML标签、Javascript等,对搜索多余的信息,如果抓取到的网页不经过处理就会使搜索变得不够精确。
让爬虫程序能继续运行下去,就得抓取这个网页上的其它URL,所以要用正则将这个网页上的所有URL都取出来放到一个队列里。用同样的方法继续抓取网页,这里将运用到多线程技术。
为了对文档进行索引,Lucene提供了五个基础的类,他们分别是Document,Field,IndexWriter,Analyzer,Directory Document是用来描述文档的,这里的文档可以指一个HTML页面,一封电子邮件,或者是一个文本文件。一个Document对象由多个Field对象组成的。可以把一个Document对象想象成数据库中的一个记录,而每个Field对象就是记录的一个字段。在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由Analyzer来做的。Analyzer类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的Analyzer。Analyzer把分词后的内容交给IndexWriter来建立索引。
论文目录:
END
联系我
获取更多资源
学习更上一层楼
pyspider 爬虫教程 (2):AJAX 和 HTTP
网站优化 • 优采云 发表了文章 • 0 个评论 • 66 次浏览 • 2022-05-07 07:05
编译:足兆叉虫,英文:pyspider
/a/77870
在上一篇教程《》中,我们使用 self.crawl API 抓取豆瓣电影的 HTML 内容,并使用 CSS 选择器解析了一些内容。不过,现在的网站通过使用 AJAX 等技术,在你与服务器交互的同时,不用重新加载整个页面。但是,这些交互手段,让抓取变得稍微难了一些:你会发现,这些网页在抓回来后,和浏览器中的并不相同。你需要的信息并不在返回 HTML 代码中。
在这一篇教程中,我们会讨论这些技术 和 抓取他们的方法。
AJAX
AJAX 是 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)的缩写。AJAX 通过使用原有的 web 标准组件,实现了在不重新加载整个页面的情况下,与服务器进行数据交互。例如在新浪微博中,你可以展开一条微博的评论,而不需要重新加载,或者打开一个新的页面。但是这些内容并不是一开始就在页面中的(这样页面就太大了),而是在你点击的时候被加载进来的。这就导致了你抓取这个页面的时候,并不能获得这些评论信息(因为你没有『展开』)。
AJAX 的一种常见用法是使用 AJAX 加载 JSON 数据,然后在浏览器端渲染。如果能直接抓取到 JSON 数据,会比 HTML 更容易解析。
当一个网站使用了 AJAX 的时候,除了用 pyspider 抓取到的页面和浏览器看到的不同以外。你在浏览器中打开这样的页面,或者点击『展开』的时候,常常会看到『加载中』或者类似的图标/动画。例如,当你尝试抓取:
你会发现电影是『载入中…』
找到真实的请求
由于 AJAX 实际上也是通过 HTTP 传输数据的,所以我们可以通过 Chrome Developer Tools 找到真实的请求,直接发起真实请求的抓取就可以获得数据了。
打开一个新窗口
按 Ctrl+Shift+I (在 Mac 上请按 Cmd+Opt+I) 打开开发者工具。
切换到网络( Netwotk 面板)
在窗口中打开
在页面加载的过程中,你会在面板中看到所有的资源请求。
AJAX 一般是通过 XMLHttpRequest 对象接口发送请求的,XMLHttpRequest 一般被缩写为 XHR。点击网络面板上漏斗形的过滤按钮,过滤出 XHR 请求。挨个查看每个请求,通过访问路径和预览,找到包含信息的请求:%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
在豆瓣这个例子中,XHR 请求并不多,可以挨个查看来确认。但在 XHR 请求较多的时候,可能需要结合触发动作的时间,请求的路径等信息帮助在大量的请求中找到包含信息的关键请求。这需要抓取或者前端的相关经验。所以,有一个我一直在提的观点,学习抓取的最好方法是:学会写网站。
现在可以在新窗口中打开 %E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0,你会看到包含电影数据的 JSON 原始数据。推荐安装 JSONView(Firfox版)插件,这样可以看到更好看的 JSON 格式,展开折叠列等功能。然后,我们根据 JSON 数据,编写一个提取电影名和评分的脚本:
classHandler(BaseHandler):
def on_start(self):
self.crawl('',
callback=self.json_parser)
def json_parser(self,response):
return[{
"title":x['title'],
"rate":x['rate'],
"url":x['url']
}forxinresponse.json['subjects']]
你可以使用 response.json 将结果转为一个 python 的 dict 对象
你可以在 获得完整的代码,并进行调试。脚本中还有一个使用 PhantomJS 渲染的提取版本,将会在下一篇教程中介绍。 查看全部
pyspider 爬虫教程 (2):AJAX 和 HTTP
编译:足兆叉虫,英文:pyspider
/a/77870
在上一篇教程《》中,我们使用 self.crawl API 抓取豆瓣电影的 HTML 内容,并使用 CSS 选择器解析了一些内容。不过,现在的网站通过使用 AJAX 等技术,在你与服务器交互的同时,不用重新加载整个页面。但是,这些交互手段,让抓取变得稍微难了一些:你会发现,这些网页在抓回来后,和浏览器中的并不相同。你需要的信息并不在返回 HTML 代码中。
在这一篇教程中,我们会讨论这些技术 和 抓取他们的方法。
AJAX
AJAX 是 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)的缩写。AJAX 通过使用原有的 web 标准组件,实现了在不重新加载整个页面的情况下,与服务器进行数据交互。例如在新浪微博中,你可以展开一条微博的评论,而不需要重新加载,或者打开一个新的页面。但是这些内容并不是一开始就在页面中的(这样页面就太大了),而是在你点击的时候被加载进来的。这就导致了你抓取这个页面的时候,并不能获得这些评论信息(因为你没有『展开』)。
AJAX 的一种常见用法是使用 AJAX 加载 JSON 数据,然后在浏览器端渲染。如果能直接抓取到 JSON 数据,会比 HTML 更容易解析。
当一个网站使用了 AJAX 的时候,除了用 pyspider 抓取到的页面和浏览器看到的不同以外。你在浏览器中打开这样的页面,或者点击『展开』的时候,常常会看到『加载中』或者类似的图标/动画。例如,当你尝试抓取:
你会发现电影是『载入中…』
找到真实的请求
由于 AJAX 实际上也是通过 HTTP 传输数据的,所以我们可以通过 Chrome Developer Tools 找到真实的请求,直接发起真实请求的抓取就可以获得数据了。
打开一个新窗口
按 Ctrl+Shift+I (在 Mac 上请按 Cmd+Opt+I) 打开开发者工具。
切换到网络( Netwotk 面板)
在窗口中打开
在页面加载的过程中,你会在面板中看到所有的资源请求。
AJAX 一般是通过 XMLHttpRequest 对象接口发送请求的,XMLHttpRequest 一般被缩写为 XHR。点击网络面板上漏斗形的过滤按钮,过滤出 XHR 请求。挨个查看每个请求,通过访问路径和预览,找到包含信息的请求:%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
在豆瓣这个例子中,XHR 请求并不多,可以挨个查看来确认。但在 XHR 请求较多的时候,可能需要结合触发动作的时间,请求的路径等信息帮助在大量的请求中找到包含信息的关键请求。这需要抓取或者前端的相关经验。所以,有一个我一直在提的观点,学习抓取的最好方法是:学会写网站。
现在可以在新窗口中打开 %E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0,你会看到包含电影数据的 JSON 原始数据。推荐安装 JSONView(Firfox版)插件,这样可以看到更好看的 JSON 格式,展开折叠列等功能。然后,我们根据 JSON 数据,编写一个提取电影名和评分的脚本:
classHandler(BaseHandler):
def on_start(self):
self.crawl('',
callback=self.json_parser)
def json_parser(self,response):
return[{
"title":x['title'],
"rate":x['rate'],
"url":x['url']
}forxinresponse.json['subjects']]
你可以使用 response.json 将结果转为一个 python 的 dict 对象
你可以在 获得完整的代码,并进行调试。脚本中还有一个使用 PhantomJS 渲染的提取版本,将会在下一篇教程中介绍。
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTM
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-05-07 06:16
1 引言
在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验了用xslt方式一次性提取静态网页内容并转换成xml格式。留下了一个问题:javascript管理的动态内容怎样提取?那么本文就回答这个问题。
2 提取动态内容的技术部件
在上一篇python使用xslt提取网页数据中,要提取的内容是直接从网页的source code里拿到的。但是一些Ajax动态内容是在source code找不到的,就要找合适的程序库把异步或动态加载的内容加载上来,交给本项目的提取器进行提取。
python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。selenium自己不带浏览器,可以使用第三方浏览器如Firefox,Chrome等,也可以使用headless浏览器如PhantomJS在后台执行。
3 源代码和实验过程
假如我们要抓取京东手机页面的手机名称和价格(价格在网页源码是找不到的),如下图:
第一步:
利用集搜客谋数台的直观标注功能,可以极快速度自动生成一个调试好的抓取规则,其实是一个标准的xslt程序,如下图,把生成的xslt程序拷贝到下面的程序中即可。注意:本文只是记录实验过程,实际系统中,将采用多种方式把xslt程序注入到内容提取器重。
第二步:
执行如下代码(在windows10, python3.2下测试通过,下载源代码请见文章末尾的GitHub源),请注意:xslt是一个比较长的字符串,如果删除这个字符串,代码没有几行,足以见得Python之强大。
<p style="margin-top: 5px; margin-bottom: 5px; line-height: 1.5em;">#/usr/bin/pythonfrom urllib import requestfrom lxml import etreefrom selenium import webdriverimport time# 京东手机商品页面url = "http://item.jd.com/1312640.html"# 下面的xslt是通过集搜客的谋数台图形界面自动生成的xslt_root = etree.XML("""\""")# 使用webdriver.PhantomJSbrowser = webdriver.PhantomJS(executable_path='C:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')browser.get(url)time.sleep(3)transform = etree.XSLT(xslt_root)# 执行js得到整个domhtml = browser.execute_script("return document.documentElement.outerHTML")doc = etree.HTML(html)# 用xslt从dom中提取需要的字段result_tree = transform(doc)print(result_tree)<br /></p>
第三步:
下图可以看到,网页中的手机名称和价格被正确抓取下来了
End.
作者:fullerhua(中国统计网特邀认证作者)
本文为中国统计网原创文章,需要转载请联系中国统计网( ),转载时请注明作者及出处,并保留本文链接。
更多精彩,长按下方图片中的二维码,下载APP查看。
查看全部
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTM
1 引言
在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验了用xslt方式一次性提取静态网页内容并转换成xml格式。留下了一个问题:javascript管理的动态内容怎样提取?那么本文就回答这个问题。
2 提取动态内容的技术部件
在上一篇python使用xslt提取网页数据中,要提取的内容是直接从网页的source code里拿到的。但是一些Ajax动态内容是在source code找不到的,就要找合适的程序库把异步或动态加载的内容加载上来,交给本项目的提取器进行提取。
python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。selenium自己不带浏览器,可以使用第三方浏览器如Firefox,Chrome等,也可以使用headless浏览器如PhantomJS在后台执行。
3 源代码和实验过程
假如我们要抓取京东手机页面的手机名称和价格(价格在网页源码是找不到的),如下图:
第一步:
利用集搜客谋数台的直观标注功能,可以极快速度自动生成一个调试好的抓取规则,其实是一个标准的xslt程序,如下图,把生成的xslt程序拷贝到下面的程序中即可。注意:本文只是记录实验过程,实际系统中,将采用多种方式把xslt程序注入到内容提取器重。
第二步:
执行如下代码(在windows10, python3.2下测试通过,下载源代码请见文章末尾的GitHub源),请注意:xslt是一个比较长的字符串,如果删除这个字符串,代码没有几行,足以见得Python之强大。
<p style="margin-top: 5px; margin-bottom: 5px; line-height: 1.5em;">#/usr/bin/pythonfrom urllib import requestfrom lxml import etreefrom selenium import webdriverimport time# 京东手机商品页面url = "http://item.jd.com/1312640.html"# 下面的xslt是通过集搜客的谋数台图形界面自动生成的xslt_root = etree.XML("""\""")# 使用webdriver.PhantomJSbrowser = webdriver.PhantomJS(executable_path='C:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')browser.get(url)time.sleep(3)transform = etree.XSLT(xslt_root)# 执行js得到整个domhtml = browser.execute_script("return document.documentElement.outerHTML")doc = etree.HTML(html)# 用xslt从dom中提取需要的字段result_tree = transform(doc)print(result_tree)<br /></p>
第三步:
下图可以看到,网页中的手机名称和价格被正确抓取下来了
End.
作者:fullerhua(中国统计网特邀认证作者)
本文为中国统计网原创文章,需要转载请联系中国统计网( ),转载时请注明作者及出处,并保留本文链接。
更多精彩,长按下方图片中的二维码,下载APP查看。
使用Python抓取同花顺资金流数据
网站优化 • 优采云 发表了文章 • 0 个评论 • 161 次浏览 • 2022-05-06 22:22
今天我们通过一个例子来介绍python爬取数据的一般步骤,用到的工具包括python的经典模块requests和BeautifulSoup,另外结合刚学习的任务流工具TaskFlow来完成代码开发。
我们先来看一下要爬取的数据,网址是,通过chrome的开发者工具分析我们可以比较容易找到后台数据加载网址为
{page_num}/ajax/1/free/1/
其中page_num的位置为要查询第几页的数据,在网页上看到概念一共有6页数据,所以page_num取值为1-6
图示1
这里有个小技巧,可以先点击图示1左上角的清空按钮,把已经加载的网址先清理掉,然后在原始网页上点第二页,就能看到图片左下角新加载的网址,点开右边“Preview” 看到资金流数据相关的内容,就能确定这个网址是用来加载数据的。
在chrome浏览器中输入 ,并打开chrome开发者工具,在网页源码中找到数据所在table标签为
<br /> ...<br /><br />
抓取数据的完整源码如下
import time<br /><br />import requests<br />from bs4 import BeautifulSoup<br />from taskflow import engines<br />from taskflow.patterns import linear_flow<br />from taskflow.task import Task<br /><br />REQUEST_HEADER = {<br /> 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}<br /><br /><br />class MoneyFlowDownload(Task):<br /> """<br /> 下载资金流数据<br /> 数据源地址:http://data.10jqka.com.cn/funds/gnzjl/<br /><br /> """<br /> BASE_URl = {<br /> "concept": 'http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/%s/ajax/1/free/1/',<br /> }<br /><br /> def execute(self, bizdate, *args, **kwargs):<br /><br /> for name, base_url in self.BASE_URl.items():<br /> # 爬取数据的存储路径<br /> dt_path = '/data/%s_%s.csv' % (bizdate, name)<br /><br /> with open(dt_path, "a+") as f:<br /> # 记录数据文件的当前位置<br /> pos = f.tell()<br /> f.seek(0)<br /> lines = f.readlines()<br /> # 读取文件中的全部数据并将第一列存储下来作为去重依据,防止爬虫意外中断后重启程序时,重复写入相同<br /> crawled_list = list(map(lambda line: line.split(",")[0], lines))<br /> f.seek(pos)<br /> # 循环500次,从第一页开始爬取数据,当页面没有数据时终端退出循环<br /> for i in range(1, 500):<br /> print("start crawl %s, %s" % (name, base_url % i))<br /> web_source = requests.get(base_url % i, headers=REQUEST_HEADER)<br /> soup = BeautifulSoup(web_source.content.decode("gbk"), 'lxml')<br /> table = soup.select('.J-ajax-table')[0]<br /> tbody = table.select('tbody tr')<br /> # 当tbody为空时,则说明当前页已经没有数据了,此时终止循环<br /> if len(tbody) == 0:<br /> break<br /> for tr in tbody:<br /> fields = tr.select('td')<br /> # 将每行记录第一列去掉,第一列为序号,没有存储必要<br /> record = [field.text.strip() for field in fields[1:]]<br /> # 如果记录还没有写入文件中,则执行写入操作,否则跳过这行写入<br /> if record[0] not in crawled_list:<br /> f.writelines([','.join(record) + '\n'])<br /> # 同花顺网站有反爬虫的机制,爬取速度过快很可能被封<br /> time.sleep(1)<br /><br /><br />if __name__ == '__main__':<br /> bizdate = '20200214'<br /> tasks = [<br /> MoneyFlowDownload('moneyflow data download')<br /> ]<br /> flow = linear_flow.Flow('ths data download').add(*tasks)<br /> e = engines.load(flow, store={'bizdate': bizdate})<br /> e.run()<br />
执行程序后,在dt_path位置已经存储了概念的资金流数据,文件名为20200214_concept.csv,内容大致如下:
钛白粉,1008.88,6.29%,7.68,6.21,1.47,7,金浦钛业,10.04%,2.96<br />磷化工,916.833,2.42%,37.53,34.78,2.75,28,六国化工,9.97%,4.08<br />光刻胶,1435.68,2.40%,43.51,44.31,-0.80,20,晶瑞股份,10.01%,42.99<br />
此时就完成了同花顺概念分类的资金流数据的爬取,之后可以每天定时启动任务抓取数据进行分析。 查看全部
使用Python抓取同花顺资金流数据
今天我们通过一个例子来介绍python爬取数据的一般步骤,用到的工具包括python的经典模块requests和BeautifulSoup,另外结合刚学习的任务流工具TaskFlow来完成代码开发。
我们先来看一下要爬取的数据,网址是,通过chrome的开发者工具分析我们可以比较容易找到后台数据加载网址为
{page_num}/ajax/1/free/1/
其中page_num的位置为要查询第几页的数据,在网页上看到概念一共有6页数据,所以page_num取值为1-6
图示1
这里有个小技巧,可以先点击图示1左上角的清空按钮,把已经加载的网址先清理掉,然后在原始网页上点第二页,就能看到图片左下角新加载的网址,点开右边“Preview” 看到资金流数据相关的内容,就能确定这个网址是用来加载数据的。
在chrome浏览器中输入 ,并打开chrome开发者工具,在网页源码中找到数据所在table标签为
<br /> ...<br /><br />
抓取数据的完整源码如下
import time<br /><br />import requests<br />from bs4 import BeautifulSoup<br />from taskflow import engines<br />from taskflow.patterns import linear_flow<br />from taskflow.task import Task<br /><br />REQUEST_HEADER = {<br /> 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}<br /><br /><br />class MoneyFlowDownload(Task):<br /> """<br /> 下载资金流数据<br /> 数据源地址:http://data.10jqka.com.cn/funds/gnzjl/<br /><br /> """<br /> BASE_URl = {<br /> "concept": 'http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/%s/ajax/1/free/1/',<br /> }<br /><br /> def execute(self, bizdate, *args, **kwargs):<br /><br /> for name, base_url in self.BASE_URl.items():<br /> # 爬取数据的存储路径<br /> dt_path = '/data/%s_%s.csv' % (bizdate, name)<br /><br /> with open(dt_path, "a+") as f:<br /> # 记录数据文件的当前位置<br /> pos = f.tell()<br /> f.seek(0)<br /> lines = f.readlines()<br /> # 读取文件中的全部数据并将第一列存储下来作为去重依据,防止爬虫意外中断后重启程序时,重复写入相同<br /> crawled_list = list(map(lambda line: line.split(",")[0], lines))<br /> f.seek(pos)<br /> # 循环500次,从第一页开始爬取数据,当页面没有数据时终端退出循环<br /> for i in range(1, 500):<br /> print("start crawl %s, %s" % (name, base_url % i))<br /> web_source = requests.get(base_url % i, headers=REQUEST_HEADER)<br /> soup = BeautifulSoup(web_source.content.decode("gbk"), 'lxml')<br /> table = soup.select('.J-ajax-table')[0]<br /> tbody = table.select('tbody tr')<br /> # 当tbody为空时,则说明当前页已经没有数据了,此时终止循环<br /> if len(tbody) == 0:<br /> break<br /> for tr in tbody:<br /> fields = tr.select('td')<br /> # 将每行记录第一列去掉,第一列为序号,没有存储必要<br /> record = [field.text.strip() for field in fields[1:]]<br /> # 如果记录还没有写入文件中,则执行写入操作,否则跳过这行写入<br /> if record[0] not in crawled_list:<br /> f.writelines([','.join(record) + '\n'])<br /> # 同花顺网站有反爬虫的机制,爬取速度过快很可能被封<br /> time.sleep(1)<br /><br /><br />if __name__ == '__main__':<br /> bizdate = '20200214'<br /> tasks = [<br /> MoneyFlowDownload('moneyflow data download')<br /> ]<br /> flow = linear_flow.Flow('ths data download').add(*tasks)<br /> e = engines.load(flow, store={'bizdate': bizdate})<br /> e.run()<br />
执行程序后,在dt_path位置已经存储了概念的资金流数据,文件名为20200214_concept.csv,内容大致如下:
钛白粉,1008.88,6.29%,7.68,6.21,1.47,7,金浦钛业,10.04%,2.96<br />磷化工,916.833,2.42%,37.53,34.78,2.75,28,六国化工,9.97%,4.08<br />光刻胶,1435.68,2.40%,43.51,44.31,-0.80,20,晶瑞股份,10.01%,42.99<br />
此时就完成了同花顺概念分类的资金流数据的爬取,之后可以每天定时启动任务抓取数据进行分析。
Google是如何抓取JavaScript 的?
网站优化 • 优采云 发表了文章 • 0 个评论 • 54 次浏览 • 2022-05-05 21:00
导语
Google 不能处理 JavaScript ?Audette Audette 分享了一系列测试结果,看看什么类型的 JavaScript 功能会被 Google 抓取和收录吧!
1. 我们进行了一系列测试,已证实 Google 能以多种方式执行和收录 JavaScript。我们也确认 Google 能渲染整个页面并读取 DOM,由此能收录动态生成的内容。
2. DOM 中的 SEO 信号(页面标题、meta 描述、canonical 标签、meta robots 标签等)都被关注到。动态插入 DOM 的内容都也能被抓取和收录。此外,在某些案例中,DOM 甚至可能比 HTML 源码语句更优先。虽然这需要做更多的工作,但这是我们好几个测试中的一个。
Google 执行 JavaScript & 读取 DOM
早在 2008 年, Google 就 成功抓取 JavaScript,但很可能局限于某种方式。
而在今天,可以明确的是,Google 不仅能制定出他们抓取和收录的 JavaScript 类型,而且在渲染整个 web 页面上取得了显著进步(特别在最近的 12 到 18 个月)。
在 Merkle,我们的 SEO 技术团队想更好地理解谷歌爬虫能抓取和收录什么类型的 JavaSscript 事件。经过研究,我们发现令人瞠目的结果,并已证实 Google 不仅能执行各种 JavaScript 事件,而且能收录动态生成的内容。怎么样做到的?Google 能读取 DOM。
DOM 是什么?
很多搞 SEO 的都不理解什么是 Document Object Model(DOM)。
当浏览器请求页面时会发生什么,而 DOM 又是如何参与进来的。
当用于 web 浏览器,DOM 本质上是一个应用程序的接口,或 API,用于标记和构造数据(如 HTML 和 XML)。该接口允许 web 浏览器将它们进行组合而构成文档。
DOM 也定义了如何对结构进行获取和操作。虽然 DOM 是与语言无关的 API (不是捆绑在特定编程语言或库),但它普遍应用于 web 应用程序的 JavaScript 和 动态内容。
DOM 代表了接口,或“桥梁”,将 web 页面与编程语言连接起来。解析 HTML 和执行 JavaScript 的结果就是 DOM。web 页面的内容不(不仅)是源码,是 DOM。这使它变得非常重要。
我们兴奋地发现 Google 能够读取 DOM,并能解析信号和动态插入的内容,例如 title 标签、页面文本、head 标签和 meta 注解(如:rel = canonical)。可阅读其中的完整细节。
因为想知道什么样的 JavaScript 功能会被抓取和收录,我们单独对 谷歌爬虫 创建一系列测试。通过创建控件,确保 URL 活动能被独立理解。下面,让我们详细划分出一些有趣的测试结果。它们被分为 5 类:
JavaScript 重定向
JavaScript 链接
动态插入内容
动态插入 Meta 数据 和页面元素
一个带有 rel = “nofollow” 的重要例子
例子:一个用来测试谷歌爬虫理解 JavaScript 能力的页面。
1.JavaScript 重定向
我们首先测试了常见的 JavaScript 重定向,用不同方式表示的 URL 会有什么样结果呢?我们选择了 window.location 对象进行两个测试:Test A 以绝对路径 URL 调用 window.location,而 Test B 使用相对路径。
结果:该重定向很快被 Google 跟踪。从收录来看,它们被解释为 301 - 最终状态的 URL 取代了 Google 收录里的重定向 URL。
在随后的测试中,我们在一个权威网页上,利用完全相同的内容,完成一次利用 JavaScript 重定向到同一个站点的新页面。而原始 URL 是排在 Google 热门查询的首页。
结果:果然,重定向被 Google 跟踪,而原始页面并没有被收录。而新 URL 被收录了,并立刻排在相同查询页面内的相同位置。这让我们很惊喜,以排名的角度上看,视乎表明了JavaScript 重定向行为(有时)很像永久性的 301 重定向。
下次,你的客户想要为他们的网站完成 JavaScript 重定向移动,你可能不需要回答,或回答:“请不要”。因为这似乎有一个转让排名信号的关系。支持这一结论是引用了 Google 指南:
使用 JavaScript 为用户进行重定向,可能是一个合法的做法。例如,如果你将已登录用户重定向到一个内部页面,你可以使用 JavaScript 完成这一操作。当仔细检查 JavaScript 或其他重定向方法时,以确保你的站点遵循我们的指南,并考虑到其意图。记住 301 重定向跳转到你网站下是最好的,但如果你没有权限访问你网站服务器,你可以为此使用 JavaScript 重定向。
2.JavaScript 链接
我们用多种编码方式测试了不同类型的 JS 链接。
我们测试下拉菜单的链接。历史上的搜素引擎一直不能跟踪这类型的链接。我们想确定 onchange 事件处理器是否会被跟踪。重要的是,这只是执行特定的类型,而我们需要是:其它改动后的影响,而不像上面 JavaScript 重定向的强制操作。
例子: Google Work 页面的语言选择下拉菜单。
结果:链接被完整地抓取和跟踪。
我们也测试了常见的 JavaScript 链接。下面是最常见类型的 JavaScript 链接,而传统的 SEO 则推荐纯文本。这些测试包括 JavaScript 链接代码:
·作用于外部 href 键-值对(AVP),但在一个标签内(“onClick”)
·作用 href 内部 AVP(“javascript : window.location”)
·作用于 a 标签外部,但在 href 内调用 AVP(“javascript : openlink()”)
·其它
结果:链接被完整抓取和跟踪。
我们下一个测试是更进一步地测试事件处理器,如上面测试的 onchange。具体地说,我们希望利用鼠标移动的事件处理器,然后隐藏 URL 变量 ,该变量只在事件处理函数(在该案例是 onmousedown 和 onmouseout)被触发时执行。
结果:链接被完整抓取和跟踪。
构造链接:我们知道 Google 能执行 JavaScript,但想确认它们是否能读取代码里的变量。所以在该测试中,我们连接能构造 URL 字符串的字符。
结果:链接被完整抓取和跟踪。
3.动态插入内容
很明显,这些都是重点:动态插入文本、图像、链接和导航。优质的文本内容对搜索引擎理解网页主题和内容是至关重要的。在这个动态网站的时代,它的重要性是无需质疑的。
这些测试,设计出来是为了检查在两个不同场景下动态插入文本的结果。
1. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码内的。
2. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码外的(在一个外部 JavaScript 文件内)。
结果:在两个案例中,文本都能被抓取和收录,并且页面是根据该内容进行排名。爽!
为了了解更多相关信息,我们测试了一个通过 JavaScript 编写的客户端全局导航,而导航里的链接都是通过 document.writeIn 函数插入,并且确定它们能被完全抓取和跟踪。应该指出的是:Google 能解释使用 AngularJS 框架 和 HTML5 History API(pushState)构建的网站,能渲染和收录它,并能像传统静态网页一样排名。这就是 不禁止谷歌爬虫 获取外部文件和 JavaScript 的重要性,而且这也许是 Google 正在从 《支持 Ajax 的 SEO 指南》 中移除它的原因。当你能简单地渲染整个页面时候,谁还需要 HTML 快照呢?
经过测试后发现,不管什么类型的内容,都是同样的结果。例如,图像加载到 DOM 后会被抓取和收录。我们甚至做了这样的一个测试:通过动态生成 结构数据来制作 breadcrumb(面包屑导航),并将其插入 DOM。结果呢? 成功插入后的面包屑出现在搜索结果中了 (search engine results page)。
值得注意的是,Google 现在 推荐用 JSON-LD 标记 形成结构化数据。我敢肯定将来会出现更多基于此的东西。
4.动态插入 Meta 数据 & 页面元素
我们将各种对 SEO 至关重要的标签动态插入到 DOM:
Title 元素
Meta 描述
Meta robots
Canonical tags
结果:在所有案例中,标签都能被抓取,其表现就像 HTML 源码里的元素一样。
一个有趣的补充实验帮助我们理解优先顺序。当存在冲突信号时,哪一个会胜出呢?如果源码里有 noindex、nofollow 标签,而 DOM 里有 noindex、follow 标签的话,将会发生什么呢?在这协议里,HTTP x-robots 响应头部的行为如何作为另一个变量?这将是未来综合测试的一部分。然而,我们的测试显示:当冲突时,Google 会无视源码里的标签,而支持 DOM。
1.一个带有 rel =“nofollow” 的重要例子
我们想测试 Google 如何应对出现在源码和 DOM 的链路级别的 nofollow 属性。我们也因此创建了一个没有应用 nofollow 的控件。
对于 nofollow ,我们分别单独测试源码 vs DOM 生成的注解。
源码里的 nofollow 正如我们所期待的那样运行(链接没被跟踪)。而 DOM 里的 nofollow 却失效(链接被跟踪,并且页面被收录)。为什么?因为在 DOM 里修改 href 元素的操作发生得太晚了:Google 在执行添加 rel=”nofollow” 的 JavaScript 函数前,已准备好抓取链接和队列等待着 URL。然而,如果将带有 href =”nofollow”的 a 元素插入到 DOM,nofollow 和链接因在同一时刻插入,所以会被跟踪。
结果
从历史角度上看,各种 SEO 推荐是在任何可能的时候,要尽可能专注 ‘纯文本’ 内容。而动态生成内容、AJAX 和 JavaScript 链接会损害主流搜索引擎的 SEO。显然,这对 Google 不再是问题。 JavaScript 链接以类似普通的 HTML 链接方式运行(这只是表面,而我们不知道幕后程序进行了什么操作)。
·JavaScript 重定向都会以类似于 301 重定向方式对待。
·动态插入内容,甚至 meta 标签,如 rel canonical 注解,无论在 HTML 源码,还是在最初 HTML 被解析后触发 JavaScript 生成 DOM ,都以同等方式对待。
·Google 视乎能完全渲染页面和理解 DOM ,而不仅是源码。实在是令人可不思议!(记得允许谷歌爬虫获取那些外部文件和 JavaScript。)
Google 已经在创新方面,以惊人的速度将其它搜索引擎甩在身后。我们希望看到其它搜索引擎能有同样类型的创新。如果他们要保持竞争力,并在 web 新时代取得实质性进展,这意味着它们要更好地支持 HTML5、JavaScript 和 动态网站。
对于 SEO,那些没有理解上述基本概念和 Google 技术的人,应该好好研究和学习,以赶上当前技术。如果你不把 DOM 考虑在内,您可能会丢失一半份额。
原文:
关于21CTO社区
是中国互联网第一技术人脉与社交平台。我们为国内最优秀的开发者提供社交、学习等产品,帮助企业快速对接开发者,包括人才招聘,项目研发,顾问咨询服务。
看微信文章不过瘾,请移步到网站,诚挚欢迎您加入社区作者团队。
网站地址:
投稿邮箱: 查看全部
Google是如何抓取JavaScript 的?
导语
Google 不能处理 JavaScript ?Audette Audette 分享了一系列测试结果,看看什么类型的 JavaScript 功能会被 Google 抓取和收录吧!
1. 我们进行了一系列测试,已证实 Google 能以多种方式执行和收录 JavaScript。我们也确认 Google 能渲染整个页面并读取 DOM,由此能收录动态生成的内容。
2. DOM 中的 SEO 信号(页面标题、meta 描述、canonical 标签、meta robots 标签等)都被关注到。动态插入 DOM 的内容都也能被抓取和收录。此外,在某些案例中,DOM 甚至可能比 HTML 源码语句更优先。虽然这需要做更多的工作,但这是我们好几个测试中的一个。
Google 执行 JavaScript & 读取 DOM
早在 2008 年, Google 就 成功抓取 JavaScript,但很可能局限于某种方式。
而在今天,可以明确的是,Google 不仅能制定出他们抓取和收录的 JavaScript 类型,而且在渲染整个 web 页面上取得了显著进步(特别在最近的 12 到 18 个月)。
在 Merkle,我们的 SEO 技术团队想更好地理解谷歌爬虫能抓取和收录什么类型的 JavaSscript 事件。经过研究,我们发现令人瞠目的结果,并已证实 Google 不仅能执行各种 JavaScript 事件,而且能收录动态生成的内容。怎么样做到的?Google 能读取 DOM。
DOM 是什么?
很多搞 SEO 的都不理解什么是 Document Object Model(DOM)。
当浏览器请求页面时会发生什么,而 DOM 又是如何参与进来的。
当用于 web 浏览器,DOM 本质上是一个应用程序的接口,或 API,用于标记和构造数据(如 HTML 和 XML)。该接口允许 web 浏览器将它们进行组合而构成文档。
DOM 也定义了如何对结构进行获取和操作。虽然 DOM 是与语言无关的 API (不是捆绑在特定编程语言或库),但它普遍应用于 web 应用程序的 JavaScript 和 动态内容。
DOM 代表了接口,或“桥梁”,将 web 页面与编程语言连接起来。解析 HTML 和执行 JavaScript 的结果就是 DOM。web 页面的内容不(不仅)是源码,是 DOM。这使它变得非常重要。
我们兴奋地发现 Google 能够读取 DOM,并能解析信号和动态插入的内容,例如 title 标签、页面文本、head 标签和 meta 注解(如:rel = canonical)。可阅读其中的完整细节。
因为想知道什么样的 JavaScript 功能会被抓取和收录,我们单独对 谷歌爬虫 创建一系列测试。通过创建控件,确保 URL 活动能被独立理解。下面,让我们详细划分出一些有趣的测试结果。它们被分为 5 类:
JavaScript 重定向
JavaScript 链接
动态插入内容
动态插入 Meta 数据 和页面元素
一个带有 rel = “nofollow” 的重要例子
例子:一个用来测试谷歌爬虫理解 JavaScript 能力的页面。
1.JavaScript 重定向
我们首先测试了常见的 JavaScript 重定向,用不同方式表示的 URL 会有什么样结果呢?我们选择了 window.location 对象进行两个测试:Test A 以绝对路径 URL 调用 window.location,而 Test B 使用相对路径。
结果:该重定向很快被 Google 跟踪。从收录来看,它们被解释为 301 - 最终状态的 URL 取代了 Google 收录里的重定向 URL。
在随后的测试中,我们在一个权威网页上,利用完全相同的内容,完成一次利用 JavaScript 重定向到同一个站点的新页面。而原始 URL 是排在 Google 热门查询的首页。
结果:果然,重定向被 Google 跟踪,而原始页面并没有被收录。而新 URL 被收录了,并立刻排在相同查询页面内的相同位置。这让我们很惊喜,以排名的角度上看,视乎表明了JavaScript 重定向行为(有时)很像永久性的 301 重定向。
下次,你的客户想要为他们的网站完成 JavaScript 重定向移动,你可能不需要回答,或回答:“请不要”。因为这似乎有一个转让排名信号的关系。支持这一结论是引用了 Google 指南:
使用 JavaScript 为用户进行重定向,可能是一个合法的做法。例如,如果你将已登录用户重定向到一个内部页面,你可以使用 JavaScript 完成这一操作。当仔细检查 JavaScript 或其他重定向方法时,以确保你的站点遵循我们的指南,并考虑到其意图。记住 301 重定向跳转到你网站下是最好的,但如果你没有权限访问你网站服务器,你可以为此使用 JavaScript 重定向。
2.JavaScript 链接
我们用多种编码方式测试了不同类型的 JS 链接。
我们测试下拉菜单的链接。历史上的搜素引擎一直不能跟踪这类型的链接。我们想确定 onchange 事件处理器是否会被跟踪。重要的是,这只是执行特定的类型,而我们需要是:其它改动后的影响,而不像上面 JavaScript 重定向的强制操作。
例子: Google Work 页面的语言选择下拉菜单。
结果:链接被完整地抓取和跟踪。
我们也测试了常见的 JavaScript 链接。下面是最常见类型的 JavaScript 链接,而传统的 SEO 则推荐纯文本。这些测试包括 JavaScript 链接代码:
·作用于外部 href 键-值对(AVP),但在一个标签内(“onClick”)
·作用 href 内部 AVP(“javascript : window.location”)
·作用于 a 标签外部,但在 href 内调用 AVP(“javascript : openlink()”)
·其它
结果:链接被完整抓取和跟踪。
我们下一个测试是更进一步地测试事件处理器,如上面测试的 onchange。具体地说,我们希望利用鼠标移动的事件处理器,然后隐藏 URL 变量 ,该变量只在事件处理函数(在该案例是 onmousedown 和 onmouseout)被触发时执行。
结果:链接被完整抓取和跟踪。
构造链接:我们知道 Google 能执行 JavaScript,但想确认它们是否能读取代码里的变量。所以在该测试中,我们连接能构造 URL 字符串的字符。
结果:链接被完整抓取和跟踪。
3.动态插入内容
很明显,这些都是重点:动态插入文本、图像、链接和导航。优质的文本内容对搜索引擎理解网页主题和内容是至关重要的。在这个动态网站的时代,它的重要性是无需质疑的。
这些测试,设计出来是为了检查在两个不同场景下动态插入文本的结果。
1. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码内的。
2. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码外的(在一个外部 JavaScript 文件内)。
结果:在两个案例中,文本都能被抓取和收录,并且页面是根据该内容进行排名。爽!
为了了解更多相关信息,我们测试了一个通过 JavaScript 编写的客户端全局导航,而导航里的链接都是通过 document.writeIn 函数插入,并且确定它们能被完全抓取和跟踪。应该指出的是:Google 能解释使用 AngularJS 框架 和 HTML5 History API(pushState)构建的网站,能渲染和收录它,并能像传统静态网页一样排名。这就是 不禁止谷歌爬虫 获取外部文件和 JavaScript 的重要性,而且这也许是 Google 正在从 《支持 Ajax 的 SEO 指南》 中移除它的原因。当你能简单地渲染整个页面时候,谁还需要 HTML 快照呢?
经过测试后发现,不管什么类型的内容,都是同样的结果。例如,图像加载到 DOM 后会被抓取和收录。我们甚至做了这样的一个测试:通过动态生成 结构数据来制作 breadcrumb(面包屑导航),并将其插入 DOM。结果呢? 成功插入后的面包屑出现在搜索结果中了 (search engine results page)。
值得注意的是,Google 现在 推荐用 JSON-LD 标记 形成结构化数据。我敢肯定将来会出现更多基于此的东西。
4.动态插入 Meta 数据 & 页面元素
我们将各种对 SEO 至关重要的标签动态插入到 DOM:
Title 元素
Meta 描述
Meta robots
Canonical tags
结果:在所有案例中,标签都能被抓取,其表现就像 HTML 源码里的元素一样。
一个有趣的补充实验帮助我们理解优先顺序。当存在冲突信号时,哪一个会胜出呢?如果源码里有 noindex、nofollow 标签,而 DOM 里有 noindex、follow 标签的话,将会发生什么呢?在这协议里,HTTP x-robots 响应头部的行为如何作为另一个变量?这将是未来综合测试的一部分。然而,我们的测试显示:当冲突时,Google 会无视源码里的标签,而支持 DOM。
1.一个带有 rel =“nofollow” 的重要例子
我们想测试 Google 如何应对出现在源码和 DOM 的链路级别的 nofollow 属性。我们也因此创建了一个没有应用 nofollow 的控件。
对于 nofollow ,我们分别单独测试源码 vs DOM 生成的注解。
源码里的 nofollow 正如我们所期待的那样运行(链接没被跟踪)。而 DOM 里的 nofollow 却失效(链接被跟踪,并且页面被收录)。为什么?因为在 DOM 里修改 href 元素的操作发生得太晚了:Google 在执行添加 rel=”nofollow” 的 JavaScript 函数前,已准备好抓取链接和队列等待着 URL。然而,如果将带有 href =”nofollow”的 a 元素插入到 DOM,nofollow 和链接因在同一时刻插入,所以会被跟踪。
结果
从历史角度上看,各种 SEO 推荐是在任何可能的时候,要尽可能专注 ‘纯文本’ 内容。而动态生成内容、AJAX 和 JavaScript 链接会损害主流搜索引擎的 SEO。显然,这对 Google 不再是问题。 JavaScript 链接以类似普通的 HTML 链接方式运行(这只是表面,而我们不知道幕后程序进行了什么操作)。
·JavaScript 重定向都会以类似于 301 重定向方式对待。
·动态插入内容,甚至 meta 标签,如 rel canonical 注解,无论在 HTML 源码,还是在最初 HTML 被解析后触发 JavaScript 生成 DOM ,都以同等方式对待。
·Google 视乎能完全渲染页面和理解 DOM ,而不仅是源码。实在是令人可不思议!(记得允许谷歌爬虫获取那些外部文件和 JavaScript。)
Google 已经在创新方面,以惊人的速度将其它搜索引擎甩在身后。我们希望看到其它搜索引擎能有同样类型的创新。如果他们要保持竞争力,并在 web 新时代取得实质性进展,这意味着它们要更好地支持 HTML5、JavaScript 和 动态网站。
对于 SEO,那些没有理解上述基本概念和 Google 技术的人,应该好好研究和学习,以赶上当前技术。如果你不把 DOM 考虑在内,您可能会丢失一半份额。
原文:
关于21CTO社区
是中国互联网第一技术人脉与社交平台。我们为国内最优秀的开发者提供社交、学习等产品,帮助企业快速对接开发者,包括人才招聘,项目研发,顾问咨询服务。
看微信文章不过瘾,请移步到网站,诚挚欢迎您加入社区作者团队。
网站地址:
投稿邮箱:
如何用Python抓取脉脉职言区的评论数据
网站优化 • 优采云 发表了文章 • 0 个评论 • 139 次浏览 • 2022-05-05 20:15
最近对脉脉的“职言”(之前叫匿名讨论区)感兴趣了,发现很多互联网公司的爆料都是从这里开始的,比如近期的互联网界愈演愈烈的“裁员潮”,在这里呈现井喷的趋势。
脉脉“职言”上关于“裁员”的讨论声量趋势分布,与百度指数的搜索量走势高度重合
由此,笔者决心用Python爬虫去上面抓取网友的讨论数据,以期后续能从中发掘一些有趣的insight,比如大家吐槽的热点(裁员潮、欠薪)、互联网公司的一些雷区(求职面试)以及一些经验(职业发展)...
笔者发现,在web端是可以登录脉脉的,这就方便了接下来的爬虫数据抓取工作。
脉脉“职言”页面
笔者在这里是采用搜索的方式定向获取数据,比如,我比较关心职言讨论区涉及“数据分析”的评论,看看大家在讨论“数据分析”的哪些方面的话题。
先观察下页面结构,笔者发现讨论区的评论是需要不断往下拉才能看到新内容的,所以这里使用了Ajax技术---在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化。
按下F12,依次点击“Network"-->"XHR",找到下拉加载时产生的请求数据。
发现脉脉“职言”要通过下拉方式才能获得新数据,由此确定它采用了ajax进行加载
重点关注它的请求URL和请求表单数据。
请求URL和表单数据,这是突破口
点击Response,发现里面的数据是json格式的,如下图所示:
数据是以json的形式进行呈现
首先分析该请求的url结构,从中发现规律,方便接下来构造请求链接。在这里,笔者采用Python标准库urllib中的parse库,用来解析和构造链接。
<p style="line-height: 1.5em;">from urllib.parse import urlparse,parse_qs,urlencode
url_name = urlparse(
'https://maimai.cn/search/gossips?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1')
url_name</p>
ParseResult(scheme='https', netloc='', path='/search/gossips', params='',query='query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1', fragment='')
依次得到协议类型、域名、路径、参数、请求和fragment。
将上面的query再进行解析,得到请求参数。
<p style="line-height: 1.5em;">parse_qs('query=%E8%A3%81%E5%91%98&limit=20&offset=20&searchTokens=%5B%22%E8%A3%81%E5%91%98%22%5D&highlight=true&sortby=&jsononly=1')</p>
{'query': ['裁员'], 'limit': ['20'], 'offset': ['20'], 'searchTokens': ['["裁员"]'], 'highlight': ['true'], 'jsononly': ['1']}
对于解析出来的结果,重点关注query、offset和searchTokens。其中,offset是偏移量,以20为单位进行增量,而query和searchTokens就是一回事,构造链接的时候写成一样的表达即可。
编写如下的链接构造函数。
<p style="line-height: 1.5em;">def key_word_search_url(keyword,offset):
data = {'query': keyword,
'limit': 20,
'offset': offset,
'searchTokens': keyword,
'highlight': 'true',
'jsononly': '1'}
search_url = 'https://maimai.cn/search/gossips?' + urlencode(data)
return search_url</p>
试试效果如何,以“社交媒体”为例,offset为20进行测试
<p style="line-height: 1.5em;">key_word_search_url('社交媒体',20)</p>
'%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&limit=20&offset=20&searchTokens=%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&highlight=true&jsononly=1'
将构造的链接放到浏览器中,看看能不能请求到数据。
json格式的数据,其实这种形式的数据是爬虫最喜欢的!
看来构造出来的请求链接是OK的!
好了,可以正式开始爬虫编写了!
第一步:载入必要的库,以及采用post方式进行登录。
<p style="line-height: 1.5em;">import requests
import re
import lxml.etree
import lxml.html
from urllib.parse import urlparse,parse_qs,urlencode
from tqdm import tqdm
from tkinter import _flatten
import pandas as pd
from fake_useragent import UserAgent
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from requests_futures.sessions import FuturesSession
from requests import Session
import time
import os
import random
ua = UserAgent() #随机生成用户代理
requests_session = FuturesSession(executor = ProcessPoolExecutor(max_workers=10),session=Session())
headers = {'user-agent':ua.random ,
'path':'/search/gossips?query=%E5%8F%A3%E7%A2%91&limit=20&offset=20&searchTokens=%5B%22%E5%8F%A3%E7%A2%91%22%5D&highlight=true&sortby=&jsononly=1',
'authority':'脉脉-成就职业梦想',
'referer':'https://maimai.cn/web/search_center?type=gossip&query=%E5%8F%A3%E7%A2%91&highlight=true',
'cookie':'''guid=GxIaBBsfEwQbEx4EGxgeVhkaGBMZHhpWGhoeBB0dHxgEGQQaGwVYT1ldRVhoe3sKGhoeBBwdHRwEGRwEGwVPWEVpChwZBB0ZHwVDWEtMS3kKHBgEExkYGQQaBBkcBU9HRVhCaQoDRUFJT20KT0FDRgoGZmd+YmECChwZBB0ZHwVeQ2FIT31PRlpaawoDHhx9ZX0KERoEGhsKfmQKWV1FTkRDfQIKGgQfBUtGRkNQRWc=; sessionid=yolyiy13px6c3wk1lc07c0tlmmmx2f4g; _buuid=558e1d44-6e93-4c65-8220-ecd9a4f050f5; seid=s1547559716083; token="AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="; uid="RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA="; session=eyJ1IjoiMzA3ODMxOTIiLCJzZWNyZXQiOiJyLVFPZTFhSFd2UE1fVmhhMHFZNjFWVE0iLCJfZXhwaXJlIjoxNTQ3NjQ2MTQ2OTQ0LCJfbWF4QWdlIjo4NjQwMDAwMH0=; session.sig=wrNrB1mK9WOBUNgU2ZFv7KMlGO0'''
}
data = {'u':'30783192',
'channel':'www',
'version':'4.0.0',
'_csrf':'semzdd8v-7gvL_7e0fLTVhsFMvglLykXUnuE',
'access_token':'1.c8169081785b6fd48f6a960f6719cfb8',
'uid':"RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA=",
'token':"AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="}
#response = requests.post('https://www.huxiu.com/v2_action/article_list', headers=headers,data = data)
response = requests_session.post('脉脉-成就职业梦想, headers=headers,data = data)
# 通过get请求返回的文本值
#print(response.result().text)</p>
第二步:使用代理IP进行数据爬取,防止爬虫被封。
<p style="line-height: 1.5em;">api_url = 'http://dynamic.goubanjia.com/dynamic/get/a93a315bcfae9120aee86832d3adca44.html?sep=3&random=true'
proxy_host = None
def update_proxy():
import urllib
global proxy_host
print('请求代理...')
proxy_host = urllib.request.urlopen(api_url).read().decode('utf-8').strip('\n')
print('取得代理IP:',proxy_host)</p>
第三步:编写解析函数,即获得页面的json数据。
<p style="line-height: 1.5em;">def parse_page(keyword,offset):
response_list = []
update_proxy()
proxies = {'http':proxy_host}
for i in range(0,offset,20):
response = requests_session.get(key_word_search_url(keyword,offset),
headers=headers,
proxies=proxies)
time.sleep(random.randint(2,6)) #在2秒~6秒钟随意切换数值,降低爬取频率,防止被封杀
# 通过get请求返回的文本值
response_list.append(response.result())
data = _flatten([i.json()['data']['gossips'] for i in response_list])
print(len(data))
return data </p>
第四步:将前面的函数整合到一起,提取json数据中重要的字段。
其中涉及:
<p style="line-height: 1.5em;">def main(keyword,offset):
name,text,total_cnt,likes,unlikes,crtime,id,is_freeze,search_order,encode_id= [],[],[],[],[],[],[],[],[],[]
for i in tqdm(parse_page(keyword,offset)):
name.append(i['gossip']['username']) #昵称
text.append(i['gossip']['text']) #文本
total_cnt.append(i['gossip']['total_cnt']) #评论数
likes.append(i['gossip']['likes']) #喜欢数
unlikes.append( i['gossip']['unlikes']) #讨厌数
crtime.append(i['gossip']['crtime']) #创建时间
id.append(i['gossip']['id']) #匿言ID
is_freeze.append(i['gossip']['is_freeze']) #匿言is_freeze
search_order.append(i['gossip']['search_order']) #匿言检索顺序
encode_id.append(i['gossip']['encode_id']) #匿言帖子编码
data = {'name':name,'text':text,'total_cnt':total_cnt,'likes':likes,'unlikes':unlikes,'crtime':crtime,'id':id,'is_freeze':is_freeze,'search_order':search_order,'encode_id':encode_id}
data_house = pd.DataFrame(data,columns=['name','text','total_cnt','likes','unlikes','crtime','id','is_freeze','search_order','encode_id'])
data_house = data_house.drop_duplicates("id")
data_house = data_house.sort_values(by='total_cnt',ascending=False)
data_house.to_csv('{}.csv'.format(keyword))
return data_house </p>
函数编写完成后,先提取部分数据试试。
<p style="line-height: 1.5em;">data_list = main('数据分析',60)</p>
工工整整的表格数据,做文本挖掘很适合!
看来效果不错!
有了这些数据以后,你可以做:
之前有过类似的分析,详情请参看:
苏格兰折耳喵:
苏格兰折耳喵:
苏格兰折耳喵: 查看全部
如何用Python抓取脉脉职言区的评论数据
最近对脉脉的“职言”(之前叫匿名讨论区)感兴趣了,发现很多互联网公司的爆料都是从这里开始的,比如近期的互联网界愈演愈烈的“裁员潮”,在这里呈现井喷的趋势。
脉脉“职言”上关于“裁员”的讨论声量趋势分布,与百度指数的搜索量走势高度重合
由此,笔者决心用Python爬虫去上面抓取网友的讨论数据,以期后续能从中发掘一些有趣的insight,比如大家吐槽的热点(裁员潮、欠薪)、互联网公司的一些雷区(求职面试)以及一些经验(职业发展)...
笔者发现,在web端是可以登录脉脉的,这就方便了接下来的爬虫数据抓取工作。
脉脉“职言”页面
笔者在这里是采用搜索的方式定向获取数据,比如,我比较关心职言讨论区涉及“数据分析”的评论,看看大家在讨论“数据分析”的哪些方面的话题。
先观察下页面结构,笔者发现讨论区的评论是需要不断往下拉才能看到新内容的,所以这里使用了Ajax技术---在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化。
按下F12,依次点击“Network"-->"XHR",找到下拉加载时产生的请求数据。
发现脉脉“职言”要通过下拉方式才能获得新数据,由此确定它采用了ajax进行加载
重点关注它的请求URL和请求表单数据。
请求URL和表单数据,这是突破口
点击Response,发现里面的数据是json格式的,如下图所示:
数据是以json的形式进行呈现
首先分析该请求的url结构,从中发现规律,方便接下来构造请求链接。在这里,笔者采用Python标准库urllib中的parse库,用来解析和构造链接。
<p style="line-height: 1.5em;">from urllib.parse import urlparse,parse_qs,urlencode
url_name = urlparse(
'https://maimai.cn/search/gossips?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1')
url_name</p>
ParseResult(scheme='https', netloc='', path='/search/gossips', params='',query='query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1', fragment='')
依次得到协议类型、域名、路径、参数、请求和fragment。
将上面的query再进行解析,得到请求参数。
<p style="line-height: 1.5em;">parse_qs('query=%E8%A3%81%E5%91%98&limit=20&offset=20&searchTokens=%5B%22%E8%A3%81%E5%91%98%22%5D&highlight=true&sortby=&jsononly=1')</p>
{'query': ['裁员'], 'limit': ['20'], 'offset': ['20'], 'searchTokens': ['["裁员"]'], 'highlight': ['true'], 'jsononly': ['1']}
对于解析出来的结果,重点关注query、offset和searchTokens。其中,offset是偏移量,以20为单位进行增量,而query和searchTokens就是一回事,构造链接的时候写成一样的表达即可。
编写如下的链接构造函数。
<p style="line-height: 1.5em;">def key_word_search_url(keyword,offset):
data = {'query': keyword,
'limit': 20,
'offset': offset,
'searchTokens': keyword,
'highlight': 'true',
'jsononly': '1'}
search_url = 'https://maimai.cn/search/gossips?' + urlencode(data)
return search_url</p>
试试效果如何,以“社交媒体”为例,offset为20进行测试
<p style="line-height: 1.5em;">key_word_search_url('社交媒体',20)</p>
'%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&limit=20&offset=20&searchTokens=%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&highlight=true&jsononly=1'
将构造的链接放到浏览器中,看看能不能请求到数据。
json格式的数据,其实这种形式的数据是爬虫最喜欢的!
看来构造出来的请求链接是OK的!
好了,可以正式开始爬虫编写了!
第一步:载入必要的库,以及采用post方式进行登录。
<p style="line-height: 1.5em;">import requests
import re
import lxml.etree
import lxml.html
from urllib.parse import urlparse,parse_qs,urlencode
from tqdm import tqdm
from tkinter import _flatten
import pandas as pd
from fake_useragent import UserAgent
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from requests_futures.sessions import FuturesSession
from requests import Session
import time
import os
import random
ua = UserAgent() #随机生成用户代理
requests_session = FuturesSession(executor = ProcessPoolExecutor(max_workers=10),session=Session())
headers = {'user-agent':ua.random ,
'path':'/search/gossips?query=%E5%8F%A3%E7%A2%91&limit=20&offset=20&searchTokens=%5B%22%E5%8F%A3%E7%A2%91%22%5D&highlight=true&sortby=&jsononly=1',
'authority':'脉脉-成就职业梦想',
'referer':'https://maimai.cn/web/search_center?type=gossip&query=%E5%8F%A3%E7%A2%91&highlight=true',
'cookie':'''guid=GxIaBBsfEwQbEx4EGxgeVhkaGBMZHhpWGhoeBB0dHxgEGQQaGwVYT1ldRVhoe3sKGhoeBBwdHRwEGRwEGwVPWEVpChwZBB0ZHwVDWEtMS3kKHBgEExkYGQQaBBkcBU9HRVhCaQoDRUFJT20KT0FDRgoGZmd+YmECChwZBB0ZHwVeQ2FIT31PRlpaawoDHhx9ZX0KERoEGhsKfmQKWV1FTkRDfQIKGgQfBUtGRkNQRWc=; sessionid=yolyiy13px6c3wk1lc07c0tlmmmx2f4g; _buuid=558e1d44-6e93-4c65-8220-ecd9a4f050f5; seid=s1547559716083; token="AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="; uid="RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA="; session=eyJ1IjoiMzA3ODMxOTIiLCJzZWNyZXQiOiJyLVFPZTFhSFd2UE1fVmhhMHFZNjFWVE0iLCJfZXhwaXJlIjoxNTQ3NjQ2MTQ2OTQ0LCJfbWF4QWdlIjo4NjQwMDAwMH0=; session.sig=wrNrB1mK9WOBUNgU2ZFv7KMlGO0'''
}
data = {'u':'30783192',
'channel':'www',
'version':'4.0.0',
'_csrf':'semzdd8v-7gvL_7e0fLTVhsFMvglLykXUnuE',
'access_token':'1.c8169081785b6fd48f6a960f6719cfb8',
'uid':"RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA=",
'token':"AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="}
#response = requests.post('https://www.huxiu.com/v2_action/article_list', headers=headers,data = data)
response = requests_session.post('脉脉-成就职业梦想, headers=headers,data = data)
# 通过get请求返回的文本值
#print(response.result().text)</p>
第二步:使用代理IP进行数据爬取,防止爬虫被封。
<p style="line-height: 1.5em;">api_url = 'http://dynamic.goubanjia.com/dynamic/get/a93a315bcfae9120aee86832d3adca44.html?sep=3&random=true'
proxy_host = None
def update_proxy():
import urllib
global proxy_host
print('请求代理...')
proxy_host = urllib.request.urlopen(api_url).read().decode('utf-8').strip('\n')
print('取得代理IP:',proxy_host)</p>
第三步:编写解析函数,即获得页面的json数据。
<p style="line-height: 1.5em;">def parse_page(keyword,offset):
response_list = []
update_proxy()
proxies = {'http':proxy_host}
for i in range(0,offset,20):
response = requests_session.get(key_word_search_url(keyword,offset),
headers=headers,
proxies=proxies)
time.sleep(random.randint(2,6)) #在2秒~6秒钟随意切换数值,降低爬取频率,防止被封杀
# 通过get请求返回的文本值
response_list.append(response.result())
data = _flatten([i.json()['data']['gossips'] for i in response_list])
print(len(data))
return data </p>
第四步:将前面的函数整合到一起,提取json数据中重要的字段。
其中涉及:
<p style="line-height: 1.5em;">def main(keyword,offset):
name,text,total_cnt,likes,unlikes,crtime,id,is_freeze,search_order,encode_id= [],[],[],[],[],[],[],[],[],[]
for i in tqdm(parse_page(keyword,offset)):
name.append(i['gossip']['username']) #昵称
text.append(i['gossip']['text']) #文本
total_cnt.append(i['gossip']['total_cnt']) #评论数
likes.append(i['gossip']['likes']) #喜欢数
unlikes.append( i['gossip']['unlikes']) #讨厌数
crtime.append(i['gossip']['crtime']) #创建时间
id.append(i['gossip']['id']) #匿言ID
is_freeze.append(i['gossip']['is_freeze']) #匿言is_freeze
search_order.append(i['gossip']['search_order']) #匿言检索顺序
encode_id.append(i['gossip']['encode_id']) #匿言帖子编码
data = {'name':name,'text':text,'total_cnt':total_cnt,'likes':likes,'unlikes':unlikes,'crtime':crtime,'id':id,'is_freeze':is_freeze,'search_order':search_order,'encode_id':encode_id}
data_house = pd.DataFrame(data,columns=['name','text','total_cnt','likes','unlikes','crtime','id','is_freeze','search_order','encode_id'])
data_house = data_house.drop_duplicates("id")
data_house = data_house.sort_values(by='total_cnt',ascending=False)
data_house.to_csv('{}.csv'.format(keyword))
return data_house </p>
函数编写完成后,先提取部分数据试试。
<p style="line-height: 1.5em;">data_list = main('数据分析',60)</p>
工工整整的表格数据,做文本挖掘很适合!
看来效果不错!
有了这些数据以后,你可以做:
之前有过类似的分析,详情请参看:
苏格兰折耳喵:
苏格兰折耳喵:
苏格兰折耳喵:
解决方案:ajax抓取网页内容属性控制用什么请求方式(get/post)
网站优化 • 优采云 发表了文章 • 0 个评论 • 187 次浏览 • 2022-09-21 17:10
ajax抓取网页内容,就是通过get请求的方式向服务器写入数据,实现网页的高效抓取。body属性控制用什么请求方式(get/post)。为一个字符串时可以使用charset属性将charset对象设置为utf-8。body的内容中需要加上data就变成了body_data。这里fromxxximportajax,urlfromxxximportbody,data。
body通常是要加上data的
ajax写的时候一般就有url的字段。可以用@框架的方式,可以走xmlhttprequest模式也可以走https模式的,看项目情况。其他的一般都是通过@可以用get/post等方式实现。
谢邀post/get/data/text/content/plain这几种就可以加上自己想加的内容,当然有时候加了也没有用,因为ajax的内容比较多,且多是一些资料性的内容,因此就为你支两招吧servlet的话,ajax容器里的service里面(tomcat里的inner类中)一般都会有一个url的字段,在它的url中我们可以输入自己想要的内容,这些内容就需要放在body中去了。
看了上面四个答案,问题都差不多,但是有一个很关键的问题没人给到答案:content-type,在form表单中,内容是放在form里的,无论他写的是什么。只有用ajax才可以变成页面上,只有在这里才可以!一般情况下http数据发过来以后,不管它是getpostputdelete还是直接post到服务器,最后都会转换成form表单发回给服务器,所以,所有请求数据的格式都是post或get的。请求服务器的格式:返回数据一般用json格式,再加上对方响应的数据的json格式即可。 查看全部
解决方案:ajax抓取网页内容属性控制用什么请求方式(get/post)
ajax抓取网页内容,就是通过get请求的方式向服务器写入数据,实现网页的高效抓取。body属性控制用什么请求方式(get/post)。为一个字符串时可以使用charset属性将charset对象设置为utf-8。body的内容中需要加上data就变成了body_data。这里fromxxximportajax,urlfromxxximportbody,data。

body通常是要加上data的
ajax写的时候一般就有url的字段。可以用@框架的方式,可以走xmlhttprequest模式也可以走https模式的,看项目情况。其他的一般都是通过@可以用get/post等方式实现。

谢邀post/get/data/text/content/plain这几种就可以加上自己想加的内容,当然有时候加了也没有用,因为ajax的内容比较多,且多是一些资料性的内容,因此就为你支两招吧servlet的话,ajax容器里的service里面(tomcat里的inner类中)一般都会有一个url的字段,在它的url中我们可以输入自己想要的内容,这些内容就需要放在body中去了。
看了上面四个答案,问题都差不多,但是有一个很关键的问题没人给到答案:content-type,在form表单中,内容是放在form里的,无论他写的是什么。只有用ajax才可以变成页面上,只有在这里才可以!一般情况下http数据发过来以后,不管它是getpostputdelete还是直接post到服务器,最后都会转换成form表单发回给服务器,所以,所有请求数据的格式都是post或get的。请求服务器的格式:返回数据一般用json格式,再加上对方响应的数据的json格式即可。
Python入门网络爬虫之精华版
网站优化 • 优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-09-11 10:45
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
转载:宁哥的小站»Python入门网络爬虫之精华版
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
Requests:<br /> import requests<br /> response = requests.get(url)<br /> content = requests.get(url).content<br /> print "response headers:", response.headers<br /> print "content:", content<br />Urllib2:<br /> import urllib2<br /> response = urllib2.urlopen(url)<br /> content = urllib2.urlopen(url).read()<br /> print "response headers:", response.headers<br /> print "content:", content<br />Httplib2:<br /> import httplib2<br /> http = httplib2.Http()<br /> response_headers, content = http.request(url, 'GET')<br /> print "response headers:", response_headers<br /> print "content:", content<br />
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.get(url=url, params=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> full_url = url+'?'+data<br /> response = urllib2.urlopen(full_url)<br />
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.post(url=url, data=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> req = urllib2.Request(url=url, data=data)<br /> response = urllib2.urlopen(req)<br />
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
import requests <br />requests_session = requests.session() <br />response = requests_session.post(url=url_login, data=data)<br />
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
response_captcha = requests_session.get(url=url_login, cookies=cookies)<br />response1 = requests.get(url_login) # 未登陆<br />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br />
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br />Requests:<br /> import requests<br /> response = requests.get(url=url, proxies=proxies)<br />Urllib2:<br /> import urllib2<br /> proxy_support = urllib2.ProxyHandler(proxies)<br /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br /> response = urllib2.urlopen(url)<br />
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
import time<br />time.sleep(1)<br />
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br />headers = {'Referer':'XXXXX'}<br />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br />Requests:<br /> response = requests.get(url=url, headers=headers)<br />Urllib2:<br /> import urllib, urllib2 <br /> req = urllib2.Request(url=url, headers=headers)<br /> response = urllib2.urlopen(req)<br />
4. 对于断线重连
def multi_session(session, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return session.post(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
或者
def multi_open(opener, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return opener.open(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
禁止所有机器人访问<br /> User-agent: *<br /> Disallow: /<br />允许所有机器人访问<br /> User-agent: *<br /> Disallow: <br />禁止特定机器人访问<br /> User-agent: BadBot<br /> Disallow: /<br />允许特定机器人访问<br /> User-agent: GoodBot<br /> Disallow: <br />禁止访问特定目录<br /> User-agent: *<br /> Disallow: /images/<br />仅允许访问特定目录<br /> User-agent: *<br /> Allow: /images/<br /> Disallow: /<br />禁止访问特定文件<br /> User-agent: *<br /> Disallow: /*.html$<br />仅允许访问特定文件<br /> User-agent: *<br /> Allow: /*.html$<br /> Disallow: /<br /> <br /> 查看全部
Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
转载:宁哥的小站»Python入门网络爬虫之精华版
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
Requests:<br /> import requests<br /> response = requests.get(url)<br /> content = requests.get(url).content<br /> print "response headers:", response.headers<br /> print "content:", content<br />Urllib2:<br /> import urllib2<br /> response = urllib2.urlopen(url)<br /> content = urllib2.urlopen(url).read()<br /> print "response headers:", response.headers<br /> print "content:", content<br />Httplib2:<br /> import httplib2<br /> http = httplib2.Http()<br /> response_headers, content = http.request(url, 'GET')<br /> print "response headers:", response_headers<br /> print "content:", content<br />
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.get(url=url, params=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> full_url = url+'?'+data<br /> response = urllib2.urlopen(full_url)<br />
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
data = {'data1':'XXXXX', 'data2':'XXXXX'}<br />Requests:data为dict,json<br /> import requests<br /> response = requests.post(url=url, data=data)<br />Urllib2:data为string<br /> import urllib, urllib2 <br /> data = urllib.urlencode(data)<br /> req = urllib2.Request(url=url, data=data)<br /> response = urllib2.urlopen(req)<br />
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。

import requests <br />requests_session = requests.session() <br />response = requests_session.post(url=url_login, data=data)<br />
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
response_captcha = requests_session.get(url=url_login, cookies=cookies)<br />response1 = requests.get(url_login) # 未登陆<br />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br />
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br />Requests:<br /> import requests<br /> response = requests.get(url=url, proxies=proxies)<br />Urllib2:<br /> import urllib2<br /> proxy_support = urllib2.ProxyHandler(proxies)<br /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br /> response = urllib2.urlopen(url)<br />
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
import time<br />time.sleep(1)<br />
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br />headers = {'Referer':'XXXXX'}<br />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br />Requests:<br /> response = requests.get(url=url, headers=headers)<br />Urllib2:<br /> import urllib, urllib2 <br /> req = urllib2.Request(url=url, headers=headers)<br /> response = urllib2.urlopen(req)<br />
4. 对于断线重连
def multi_session(session, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return session.post(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
或者
def multi_open(opener, *arg):<br /> retryTimes = 20<br /> while retryTimes>0:<br /> try:<br /> return opener.open(*arg)<br /> except:<br /> print '.',<br /> retryTimes -= 1<br />
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。

这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
禁止所有机器人访问<br /> User-agent: *<br /> Disallow: /<br />允许所有机器人访问<br /> User-agent: *<br /> Disallow: <br />禁止特定机器人访问<br /> User-agent: BadBot<br /> Disallow: /<br />允许特定机器人访问<br /> User-agent: GoodBot<br /> Disallow: <br />禁止访问特定目录<br /> User-agent: *<br /> Disallow: /images/<br />仅允许访问特定目录<br /> User-agent: *<br /> Allow: /images/<br /> Disallow: /<br />禁止访问特定文件<br /> User-agent: *<br /> Disallow: /*.html$<br />仅允许访问特定文件<br /> User-agent: *<br /> Allow: /*.html$<br /> Disallow: /<br /> <br />
ajax+ajax的内容存储在服务器.获取网页内容
网站优化 • 优采云 发表了文章 • 0 个评论 • 45 次浏览 • 2022-09-06 14:01
ajax抓取网页内容,一般是用js脚本去获取网页内容,特别是直接用requests去请求获取网页内容,然后经过编码,转化成json,然后存储。
就是请求服务器啊.每个请求都会定时分析这个html,用正则表达式匹配出某个元素,
ajax技术能够将javascript与网页交互的方式转化为json,然后再解析出页面的内容和跳转地址。ajax技术的提出,源于当时流行的html5标准。而html5标准中也提到了xmlhttprequest,即后来的ajax。使用xmlhttprequest来发送数据有三个标准可以选择,它们是activex,jsonp,xml2。
但是activex和jsonp并不兼容,只能推荐使用xml2来发送xml数据。jsonp也不能充分利用xmlhttprequest发送ajax消息。于是w3c发布了requests库来发送xml消息。后来还提供了xml2的xmlhttprequestapi。
ajax就是xmlhttprequest+ajax的json转换器这个node.js可以用
ajax在javascript技术层面是json的一种类型。
ajax既然名为“asynchronousjavascriptxmlretransform”,那么应该是同时发送两个html,xml的内容存储在服务器,json的内容存储在浏览器.
获取网页内容?显然是获取xml.那就要json.parse了。至于如何写出一个合格的xml/json/xml.js,js其实可以写很长很复杂的程序,可以有很多种。大多数情况下,只需要用框架(servlet,jstl,fiber), 查看全部
ajax+ajax的内容存储在服务器.获取网页内容
ajax抓取网页内容,一般是用js脚本去获取网页内容,特别是直接用requests去请求获取网页内容,然后经过编码,转化成json,然后存储。
就是请求服务器啊.每个请求都会定时分析这个html,用正则表达式匹配出某个元素,

ajax技术能够将javascript与网页交互的方式转化为json,然后再解析出页面的内容和跳转地址。ajax技术的提出,源于当时流行的html5标准。而html5标准中也提到了xmlhttprequest,即后来的ajax。使用xmlhttprequest来发送数据有三个标准可以选择,它们是activex,jsonp,xml2。
但是activex和jsonp并不兼容,只能推荐使用xml2来发送xml数据。jsonp也不能充分利用xmlhttprequest发送ajax消息。于是w3c发布了requests库来发送xml消息。后来还提供了xml2的xmlhttprequestapi。
ajax就是xmlhttprequest+ajax的json转换器这个node.js可以用

ajax在javascript技术层面是json的一种类型。
ajax既然名为“asynchronousjavascriptxmlretransform”,那么应该是同时发送两个html,xml的内容存储在服务器,json的内容存储在浏览器.
获取网页内容?显然是获取xml.那就要json.parse了。至于如何写出一个合格的xml/json/xml.js,js其实可以写很长很复杂的程序,可以有很多种。大多数情况下,只需要用框架(servlet,jstl,fiber),
ajax抓取网页内容的方法有很多种,ajax代理接口
网站优化 • 优采云 发表了文章 • 0 个评论 • 57 次浏览 • 2022-08-19 06:03
ajax抓取网页内容的方法有很多种,如果目标网站已经对返回正常内容做了requestlist的话,那么还可以通过爬虫代理接口完成抓取。如果网站还在对requestlist返回正常的话,在第一次抓取网页的时候,可以通过判断返回requestlist的规律完成抓取。首先判断他的返回requestlist的规律,可以通过这些规律获取这些返回的requestidxxxbooks/5000,比如做网络请求的sleep是1-3,抓取也要这样做,flooding可以做出最大点击次数,剩余抓取次数和最大点击次数差不多,通过flooding可以知道最大点击次数除以sleep来判断下一次抓取request的id有可能是多少。
然后判断get请求的返回结果是否与返回正常的不同,比如请求article.json来抓取,返回article的返回结果是两个字符串,一个是html,一个是json,那么可以试试把json转化成字符串再请求,这样抓取时就是没有返回json所对应的html内容,即从article转换出来的html里没有json字符串。
其他的爬虫代理也是这么判断的,先通过判断返回正常的返回结果来判断规律是否与返回requestlist不同再进行抓取操作。接下来可以爬取数据库里的数据,因为要抓取的对象都是由server生成请求记录的(类似爬虫请求请求记录),所以可以通过判断请求记录的规律,从数据库中直接爬取到该对象的access_token,通过这个access_token请求对象时,会被弹出验证码验证请求是否正确。最后根据规律取到这个对象的server。 查看全部
ajax抓取网页内容的方法有很多种,ajax代理接口

ajax抓取网页内容的方法有很多种,如果目标网站已经对返回正常内容做了requestlist的话,那么还可以通过爬虫代理接口完成抓取。如果网站还在对requestlist返回正常的话,在第一次抓取网页的时候,可以通过判断返回requestlist的规律完成抓取。首先判断他的返回requestlist的规律,可以通过这些规律获取这些返回的requestidxxxbooks/5000,比如做网络请求的sleep是1-3,抓取也要这样做,flooding可以做出最大点击次数,剩余抓取次数和最大点击次数差不多,通过flooding可以知道最大点击次数除以sleep来判断下一次抓取request的id有可能是多少。

然后判断get请求的返回结果是否与返回正常的不同,比如请求article.json来抓取,返回article的返回结果是两个字符串,一个是html,一个是json,那么可以试试把json转化成字符串再请求,这样抓取时就是没有返回json所对应的html内容,即从article转换出来的html里没有json字符串。
其他的爬虫代理也是这么判断的,先通过判断返回正常的返回结果来判断规律是否与返回requestlist不同再进行抓取操作。接下来可以爬取数据库里的数据,因为要抓取的对象都是由server生成请求记录的(类似爬虫请求请求记录),所以可以通过判断请求记录的规律,从数据库中直接爬取到该对象的access_token,通过这个access_token请求对象时,会被弹出验证码验证请求是否正确。最后根据规律取到这个对象的server。
ajax抓取网页内容,如何进行判断是否是转义符呢
网站优化 • 优采云 发表了文章 • 0 个评论 • 60 次浏览 • 2022-07-15 21:05
ajax抓取网页内容,如何进行判断是否是转义符呢?这里就需要我们掌握,ajax中的xmlhttprequest对象。publicclassthreadextendsserializable{privatestaticfinalintxhr=25;privatestaticfinalintxhrfile;privatestaticfinalintxhrread;privatestaticfinalintxhrtimeout;publicthread(stringname){super(name,name);}@overridepublicvoidrun(){system.out.println("请求一个资源");}}xmlhttprequest对象中定义了三个属性:name、fromserver、methods方法,其作用是判断请求属性。
publicclassxmlhttprequestextendshttpservletrequestimplementshttpservletrequestlistener{//是否是servlethttp请求,servlethttp请求是打开不了的privatestaticfinalintxhr=25;privatestaticfinalintxhrfile="s.html";privatestaticfinalintxhrworkinstance=4;publicxmlhttprequest(stringname){this.name=name;}@overridepublicvoidrun(){system.out.println("请求一个资源");}}以下代码检查一个xmlhttprequest请求是否成功。
contextxmlhttprequest=newcontext("c:\\users\\lieke\\administrator\\appdata\\microsoft\\xmlhttp");publicstaticvoidmain(string[]args){system.out.println("请求一个资源");contextxmlhttprequest.send(newstring("lyndlyyyyyyy"));}publicstaticvoidsend(newstring("lyndlyyyyyyy")){system.out.println("服务器收到请求,并把字符串回复给"+xmlhttprequest.getheader("location")+""+xmlhttprequest.getheader("username")+""+xmlhttprequest.getheader("password")+""+"enteryouraction");}。 查看全部
ajax抓取网页内容,如何进行判断是否是转义符呢

ajax抓取网页内容,如何进行判断是否是转义符呢?这里就需要我们掌握,ajax中的xmlhttprequest对象。publicclassthreadextendsserializable{privatestaticfinalintxhr=25;privatestaticfinalintxhrfile;privatestaticfinalintxhrread;privatestaticfinalintxhrtimeout;publicthread(stringname){super(name,name);}@overridepublicvoidrun(){system.out.println("请求一个资源");}}xmlhttprequest对象中定义了三个属性:name、fromserver、methods方法,其作用是判断请求属性。

publicclassxmlhttprequestextendshttpservletrequestimplementshttpservletrequestlistener{//是否是servlethttp请求,servlethttp请求是打开不了的privatestaticfinalintxhr=25;privatestaticfinalintxhrfile="s.html";privatestaticfinalintxhrworkinstance=4;publicxmlhttprequest(stringname){this.name=name;}@overridepublicvoidrun(){system.out.println("请求一个资源");}}以下代码检查一个xmlhttprequest请求是否成功。
contextxmlhttprequest=newcontext("c:\\users\\lieke\\administrator\\appdata\\microsoft\\xmlhttp");publicstaticvoidmain(string[]args){system.out.println("请求一个资源");contextxmlhttprequest.send(newstring("lyndlyyyyyyy"));}publicstaticvoidsend(newstring("lyndlyyyyyyy")){system.out.println("服务器收到请求,并把字符串回复给"+xmlhttprequest.getheader("location")+""+xmlhttprequest.getheader("username")+""+xmlhttprequest.getheader("password")+""+"enteryouraction");}。
【第195期】如何让搜索引擎抓取AJAX内容
网站优化 • 优采云 发表了文章 • 0 个评论 • 52 次浏览 • 2022-06-17 20:48
【早读君聊聊】公司产品用户的特殊性,所以在开发的时候都会顾及SEO的作用,也就是希望所开发的页面能被搜索引擎收录。但在SPA流行的年代,团队童鞋也是很希望尝试新模式,在各种冲突中做权衡,找合适的方案。
正文~~~~
越来越多的网站,开始采用"单页面结构"(Single-page application)。整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容。
这种做法的好处是用户体验好、节省流量,缺点是AJAX内容无法被搜索引擎抓取。举例来说,你有一个网站。
用户通过井号结构的URL,看到不同的内容。
但是,搜索引擎只抓取,不会理会井号,因此也就无法索引内容。为了解决这个问题,Google提出了"井号+感叹号"的结构。
当Google发现上面这样的URL,就自动抓取另一个网址:
只要你把AJAX内容放在这个网址,Google就会收录。但是问题是,"井号+感叹号"非常难看且烦琐。Twitter曾经采用这种结构。
它把
改成
结果用户抱怨连连,只用了半年就废除了。
那么,有没有什么方法,可以在保持比较直观的URL的同时,还让搜索引擎能够抓取AJAX内容?
我一直以为没有办法做到,直到前两天看到了Discourse创始人之一的Robin Ward的解决方法,不禁拍案叫绝。
Discourse是一个论坛程序,严重依赖Ajax,但是又必须让Google收录内容。它的解决方法就是放弃井号结构,采用 History API。所谓 History API,指的是不刷新页面的情况下,改变浏览器地址栏显示的URL(准确说,是改变网页的当前状态)。这里有一个例子,你点击上方的按钮,开始播放音乐。然后,再点击下面的链接,看看发生了什么事?
地址栏的URL变了,但是音乐播放没有中断!
History API 的详细介绍,超出这篇文章的范围。这里只简单说,它的作用就是在浏览器的History对象中,添加一条记录。
上面这行命令,可以让地址栏出现新的URL。History对象的pushState方法接受三个参数,新的URL就是第三个参数,前两个参数都可以是null。
目前,各大浏览器都支持这个方法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。
下面就是Robin Ward的方法。
首先,用History API替代井号结构,让每个井号都变成正常路径的URL,这样搜索引擎就会抓取每一个网页。
然后,定义一个JavaScript函数,处理Ajax部分,根据网址抓取内容(假定使用jQuery)。
再定义鼠标的click事件。
还要考虑到用户点击浏览器的"前进 / 后退"按钮。这时会触发History对象的popstate事件。
定义完上面三段代码,就能在不刷新页面的情况下,显示正常路径URL和AJAX内容。
最后,设置服务器端。
因为不使用井号结构,每个URL都是一个不同的请求。所以,要求服务器端对所有这些请求,都返回如下结构的网页,防止出现404错误。
仔细看上面这段代码,你会发现有一个noscript标签,这就是奥妙所在。
我们把所有要让搜索引擎收录的内容,都放在noscript标签之中。这样的话,用户依然可以执行AJAX操作,不用刷新页面,但是搜索引擎会收录每个网页的主要内容! 查看全部
【第195期】如何让搜索引擎抓取AJAX内容
【早读君聊聊】公司产品用户的特殊性,所以在开发的时候都会顾及SEO的作用,也就是希望所开发的页面能被搜索引擎收录。但在SPA流行的年代,团队童鞋也是很希望尝试新模式,在各种冲突中做权衡,找合适的方案。
正文~~~~
越来越多的网站,开始采用"单页面结构"(Single-page application)。整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容。
这种做法的好处是用户体验好、节省流量,缺点是AJAX内容无法被搜索引擎抓取。举例来说,你有一个网站。
用户通过井号结构的URL,看到不同的内容。
但是,搜索引擎只抓取,不会理会井号,因此也就无法索引内容。为了解决这个问题,Google提出了"井号+感叹号"的结构。
当Google发现上面这样的URL,就自动抓取另一个网址:
只要你把AJAX内容放在这个网址,Google就会收录。但是问题是,"井号+感叹号"非常难看且烦琐。Twitter曾经采用这种结构。
它把
改成
结果用户抱怨连连,只用了半年就废除了。
那么,有没有什么方法,可以在保持比较直观的URL的同时,还让搜索引擎能够抓取AJAX内容?
我一直以为没有办法做到,直到前两天看到了Discourse创始人之一的Robin Ward的解决方法,不禁拍案叫绝。
Discourse是一个论坛程序,严重依赖Ajax,但是又必须让Google收录内容。它的解决方法就是放弃井号结构,采用 History API。所谓 History API,指的是不刷新页面的情况下,改变浏览器地址栏显示的URL(准确说,是改变网页的当前状态)。这里有一个例子,你点击上方的按钮,开始播放音乐。然后,再点击下面的链接,看看发生了什么事?
地址栏的URL变了,但是音乐播放没有中断!
History API 的详细介绍,超出这篇文章的范围。这里只简单说,它的作用就是在浏览器的History对象中,添加一条记录。
上面这行命令,可以让地址栏出现新的URL。History对象的pushState方法接受三个参数,新的URL就是第三个参数,前两个参数都可以是null。
目前,各大浏览器都支持这个方法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。
下面就是Robin Ward的方法。
首先,用History API替代井号结构,让每个井号都变成正常路径的URL,这样搜索引擎就会抓取每一个网页。
然后,定义一个JavaScript函数,处理Ajax部分,根据网址抓取内容(假定使用jQuery)。
再定义鼠标的click事件。
还要考虑到用户点击浏览器的"前进 / 后退"按钮。这时会触发History对象的popstate事件。
定义完上面三段代码,就能在不刷新页面的情况下,显示正常路径URL和AJAX内容。
最后,设置服务器端。
因为不使用井号结构,每个URL都是一个不同的请求。所以,要求服务器端对所有这些请求,都返回如下结构的网页,防止出现404错误。
仔细看上面这段代码,你会发现有一个noscript标签,这就是奥妙所在。
我们把所有要让搜索引擎收录的内容,都放在noscript标签之中。这样的话,用户依然可以执行AJAX操作,不用刷新页面,但是搜索引擎会收录每个网页的主要内容!
动态网页抓不了?JavaScript入门攻略已发送~
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-06-17 20:48
var carname="Volvo";
0 3
变量命名的规则
① 由字母、数字、下划线和 $ 组成,但是不能以数字开头,如:12asd 这个名字就会报错
② 不能是关键字或保留字,比如 var、for等
③ 严格区分大小写,就是说大写和小写都是不一样的变量
0 4
数据类型
JavaScript 的数据类型分两种,一种是简单数据类型,另一种是复杂数据类型。
示例:返回的类型是一个number;
<br /> var a = 123; //var是设置一个变量 alert('hello') //一个弹窗,可以判断是否为外部引入的 console.log(a) //console.log():是在浏览器的控制台上的输出 console.log(typeof a); //typeof 判断是属于什么类型<br />
需要注意:要严格区分大小写,否则便会出现报错。
0 5
介绍几个函数
(1)Number() 将数据转换成number类型,里面的参数便是你要转变类型的数据。<br />(2)toString() String() 两种方法将数据转换成字符串类型;区别String() 可以将null 转换成"null" toString() 返回的是undefined;<br />(3)Boolean() 将数据类型转换换成布尔类型;bool 返回两种数据类型,一个是true 一个是false。在将 Boolean 类型转 Number 时,true会转为 1, false 会转为 0,这个方法不支持将数字开头带有其它字符的字符串转为数值类型,如 “12df”。
2 Python执行JS代码的方式
Python执行JS代码的三种方式;
1
使用 js2py
基本操作示例:
import js2py<br /><br /># 执行单行js语句js2py.eval_js("console.log(abcd)")>>> abcd<br /># 执行js函数add = js2py.eval_js("function add(a, b) {return a + b};")print(add(1,2))>>> 3<br /># 另一种方式js = js2py.EvalJs({})js.execute("js语句")
在js代码中引入python对象或python代码
# 在js代码中引入python对象context = js2py.EvalJs({'python_sum': sum})context.eval('python_sum(new Array(1,4,2,7))')>>> 14<br /># 在js代码中加入python代码js_code = ''' var a = 10 function f(x) {return x*x}'''context.execute(js_code)context.f("14") 或 context.f(14)>>> 196
将js代码转为python模块,再使用import 导入
# 转换js文件js2py.translate_file('example.js', 'example.py')<br /># 现在可以导入example.pyfrom example import exampleexample.someFunction()<br /><br /><br /># 转换js代码js2py.translate_js('var $ = 5')>>> """from js2py.pyjs import *# setting scopevar = Scope( JS_BUILTINS )set_global_object(var)# Code follows:var.registers(['$'])var.put('$', Js(5.0))"""
不过py2js有时候在加载一些加密函数的时候效率低的可怜,大概是因为执行
机制的不同;
py2js直接调用的nodejs引擎不过这个库用的nodejs解析语法树转成py代码,性能挺低的,还不如直接用execjs调nodejs或自己封装子进程调用。
2
使用 execjs
import execjs<br />js_code = open('file.js',encoding='utf-8').read()ctx = execjs.compile(js_code)<br /># 第一个参数为ja代码中的函数名, 后面为函数对应的参数result = ctx.call('function_name', *args)
3
使用subprocess调用node子进程
import subprocess<br /># js文件最后必须有输出,我使用的是 console.logpro = subprocess.run("node abc.js", stdout=subprocess.PIPE)# 获得标准输出_token = pro.stdout# 转一下格式token = _token.decode().strip()
3 JS动态网页抓取方式
许多时候爬虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。
一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的;
下面两种方案,可用来python爬取js执行后输出的信息。
① 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。
WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含js等的网页。
import dryscrape # 使用dryscrape库 动态抓取页面 def get_url_dynamic(url): session_req=dryscrape.Session() session_req.visit(url) #请求页面 response=session_req.body() #网页的文本 #print(response) return response get_text_line(get_url_dynamic(url)) #将输出一条文本
这里对于其余包含js的网页也是适用的,虽然可以满足抓取动态页面的要求,
但缺点还是很明显的:慢!
但想想也合理,python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回,慢一点情理之中。
除外还有很多库可以调用 webkit:PythonWebkit,PyWebKitGit,Pygt(可以用它写个浏览器),pyjamas等等,也可以实现相同的功能。
② selenium web测试框架
selenium是一个web测试框架,允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
使用 selenium webdriver 可行,但会实时打开浏览器窗口。
def get_url_dynamic2(url): driver=webdriver.Firefox() #调用本地的火狐浏览器,Chrom 甚至 Ie 也可以的 driver.get(url) #请求页面,会打开一个浏览器窗口 html_text=driver.page_source driver.quit() #print html_text return html_text get_text_line(get_url_dynamic2(url)) #将输出一条文本
不失为一条临时的解决方案,与selenium类似的框架还有一个windmill,
感觉稍复杂一些,这里就暂且不赘述了。
4解析JS
我们爬虫每次只有一个请求,但是实际上很多请求又js连带发送,所以我们需要利用爬虫解析js去实现这些请求的发送。
网页中的参数来源主要有以下四种:
这里主要介绍一下解析js,破解加密方法或者生成参数值方法,python代码模拟实现这个方法, 从而得到我们需要的请求参数。
以微博登录为例:
当我们点击登录的时候都会发送一个login请求
登录表单中的参数并不一定都是我们需要的,可以通过对比多次请求中的参数,再加上一些经验和猜想,过滤掉固定参数或服务器自带参数和用户输入的参数。
这是剩下的就是js生成的数值或加密数值;
最终得到的值:
# 图片 picture id:pcid: yf-d0efa944bb243bddcf11906cda5a46dee9b8# 用户名:su: cXdlcnRxd3Jlnonce: 2SSH2A # 未知# 密码:sp: e121946ac9273faf9c63bc0fdc5d1f84e563a4064af16f635000e49cbb2976d73734b0a8c65a6537e2e728cd123e6a34a7723c940dd2aea902fb9e7c6196e3a15ec52607fd02d5e5a28e18254105358e897996f0b9057afe2d24b491bb12ba29db3265aef533c1b57905bf02c0cee0c546f4294b0cf73a553aa1f7faf9f835e5prelt: 148 # 未知
请求参数中的用户名和密码都是经过加密处理的,如果需要模拟登录,就需要找到这个加密的方法,利用它来为我们的数据进行加密。
1)找到所需的js
要找到加密方法,首先我们需要先找到登录所需的js代码,可以使用以下3种方式:
① 找事件;在页面检查目标元素,在开发工具的子窗口里选中Events Listeners, 找到click事件,点击定位到js代码。
② 找请求;在Network中点击列表界面的对应Initiator跳转至对应js界面;
③ 通过搜索参数名进行定位;
2)登录的js代码
3)在这个submit的方法上打断点
然后输入用户名密码,先不点登录,回到dev tool点击这个按钮启用调试。
4)然后再去点登录按钮, 这时候就可以开始调试;
5)逐步执行代码的同时观察我们输入的参数, 发生变化的地方即为加密方法
如下示例:
6)上图中的加密方式是base64, 我们可以使用代码来试一下
import base64<br />a = "aaaaaaaaaaaa" # 输入的用户名print(base64.b64encode(a.encode())) # 得到的加密结果:b'YWFhYWFhYWFhYWFh'# 如果用户名包含@等特殊符号, 需要先用parse.quote()进行转义
得到的加密结果与网页上js的执行结果一致;
5爬虫中JS反爬技术
爬虫中遇到的js反爬技术(重点)
0 1
JS写cookie
requests请求得到的网页是一对JS,跟浏览器打开看到的网页源码完全不一样。
这种情况,往往是浏览器运行这段JS生成一个(或多个)cookie再带着这个cookie做二次请求。
在浏览器(chrome、Firefox都可以)里可以看到这一过程,首先把Chrome浏览器保存的该网站的cookie删除。
按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。
第一次打开“index.html”页面时返回的是521, 内容是一段JS代码;
第二次请求这个页面就得到了正常的HTML,查看两次请求的cookies,可以发现第二次请求时带上了一个cookie,而这个cookie并不是第一次请求时服务器发过来的,其实它就是JS生成的。
解决思路:研究那段JS,找到它生成cookie的算法,爬虫就可以解决这个问题。
0 2
JS加密ajax请求参数
抓某个网页里面的数据,发现网页源代码里面没有我们要的数据,麻烦之处在于数据往往是ajax请求得到的。
按F12打开Network窗口,刷新网页看看加载这个网页都下载了哪些URL,我们要的数据就在某个URL请求的结果里面。
这类URL在Chrome的Network里面的类型大多是XHR,通过观察它们的“Response”就可以发现我们要的数据。
我们可以把这个URL拷贝到地址栏,把那个参数随便改个字母,访问一下看看是不是能得到正确的结果,由此来验证它是否是很重要的加密参数。
解决思路:对于这样的加密参数,可以尝试通过debug JS来找到对应的JS加密算法,其中关键的是在Chrome里面设置“XHR/fetch Breakpoints”。
0 3
JS反调试(反debug)
前面我们都用到了Chrome 的F12去查看网页加载的过程,或者是调试JS的运行过程。
不过这种方法用多了,网站就加了反调试的策略,只有我们打开F12,就会暂停在一个“debugger”代码行,无论怎样都跳不出去。
不管我们点击多少次继续运行,它一直在这个“debugger”这里,每次都会多出一个VMxx的标签,观察“Call Stack”发现它好像陷入了一个函数的递归调用。
这个“debugger”让我们无法调试JS,但是关掉F12窗口,网页就正常加载了。
解决思路:“反-反调试”,通过“Call Stack”找到把我们带入死循环的函数,重新定义它。
JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。
0 4
JS发送鼠标点击事件
有些网站它的反爬都不是上面的方式,你从浏览器可以打开正常的页面,而在requests里面却被要求输入验证码或重定向其它网页。
可以试着从“Network”看看,比如下面这个Network流里面的信息:
认真看看后会发现,每点击页面的的链接,它都会做一个“cl.gif”的请求,它看上去是下载一个gif图片,然而并不是。
它请求时发送的参数非常多,而且这些参数都是当前页面的信息。比如包含了被点击的链接等等。
先来顺一下它的逻辑:
① JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。
② 服务器收到被点击链接的请求,会看看之前是不是已经通过cl.gif把对应信息发过来,如果发过来了就认为是合法的浏览器访问,给出正常的网页内容。
③ 因为requests没有鼠标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
解决思路:在访问链接前先访问一下cl.gif即可,关键是要研究cl.gif后的参数,把这些参数都带上问题就不大了,这样就可以绕过这个反爬策略。
END
最后:
欢迎关注「Python新手快速入门」
每天5分钟,学习一个Python小Tip!助力你成为更优秀的Python学习者~ 查看全部
动态网页抓不了?JavaScript入门攻略已发送~
var carname="Volvo";
0 3
变量命名的规则
① 由字母、数字、下划线和 $ 组成,但是不能以数字开头,如:12asd 这个名字就会报错
② 不能是关键字或保留字,比如 var、for等
③ 严格区分大小写,就是说大写和小写都是不一样的变量
0 4
数据类型
JavaScript 的数据类型分两种,一种是简单数据类型,另一种是复杂数据类型。
示例:返回的类型是一个number;
<br /> var a = 123; //var是设置一个变量 alert('hello') //一个弹窗,可以判断是否为外部引入的 console.log(a) //console.log():是在浏览器的控制台上的输出 console.log(typeof a); //typeof 判断是属于什么类型<br />
需要注意:要严格区分大小写,否则便会出现报错。
0 5
介绍几个函数
(1)Number() 将数据转换成number类型,里面的参数便是你要转变类型的数据。<br />(2)toString() String() 两种方法将数据转换成字符串类型;区别String() 可以将null 转换成"null" toString() 返回的是undefined;<br />(3)Boolean() 将数据类型转换换成布尔类型;bool 返回两种数据类型,一个是true 一个是false。在将 Boolean 类型转 Number 时,true会转为 1, false 会转为 0,这个方法不支持将数字开头带有其它字符的字符串转为数值类型,如 “12df”。
2 Python执行JS代码的方式
Python执行JS代码的三种方式;
1
使用 js2py
基本操作示例:
import js2py<br /><br /># 执行单行js语句js2py.eval_js("console.log(abcd)")>>> abcd<br /># 执行js函数add = js2py.eval_js("function add(a, b) {return a + b};")print(add(1,2))>>> 3<br /># 另一种方式js = js2py.EvalJs({})js.execute("js语句")
在js代码中引入python对象或python代码
# 在js代码中引入python对象context = js2py.EvalJs({'python_sum': sum})context.eval('python_sum(new Array(1,4,2,7))')>>> 14<br /># 在js代码中加入python代码js_code = ''' var a = 10 function f(x) {return x*x}'''context.execute(js_code)context.f("14") 或 context.f(14)>>> 196
将js代码转为python模块,再使用import 导入
# 转换js文件js2py.translate_file('example.js', 'example.py')<br /># 现在可以导入example.pyfrom example import exampleexample.someFunction()<br /><br /><br /># 转换js代码js2py.translate_js('var $ = 5')>>> """from js2py.pyjs import *# setting scopevar = Scope( JS_BUILTINS )set_global_object(var)# Code follows:var.registers(['$'])var.put('$', Js(5.0))"""
不过py2js有时候在加载一些加密函数的时候效率低的可怜,大概是因为执行
机制的不同;
py2js直接调用的nodejs引擎不过这个库用的nodejs解析语法树转成py代码,性能挺低的,还不如直接用execjs调nodejs或自己封装子进程调用。
2
使用 execjs
import execjs<br />js_code = open('file.js',encoding='utf-8').read()ctx = execjs.compile(js_code)<br /># 第一个参数为ja代码中的函数名, 后面为函数对应的参数result = ctx.call('function_name', *args)
3
使用subprocess调用node子进程
import subprocess<br /># js文件最后必须有输出,我使用的是 console.logpro = subprocess.run("node abc.js", stdout=subprocess.PIPE)# 获得标准输出_token = pro.stdout# 转一下格式token = _token.decode().strip()
3 JS动态网页抓取方式
许多时候爬虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。
一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的;
下面两种方案,可用来python爬取js执行后输出的信息。
① 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。
WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含js等的网页。
import dryscrape # 使用dryscrape库 动态抓取页面 def get_url_dynamic(url): session_req=dryscrape.Session() session_req.visit(url) #请求页面 response=session_req.body() #网页的文本 #print(response) return response get_text_line(get_url_dynamic(url)) #将输出一条文本
这里对于其余包含js的网页也是适用的,虽然可以满足抓取动态页面的要求,
但缺点还是很明显的:慢!
但想想也合理,python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回,慢一点情理之中。
除外还有很多库可以调用 webkit:PythonWebkit,PyWebKitGit,Pygt(可以用它写个浏览器),pyjamas等等,也可以实现相同的功能。
② selenium web测试框架
selenium是一个web测试框架,允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
使用 selenium webdriver 可行,但会实时打开浏览器窗口。
def get_url_dynamic2(url): driver=webdriver.Firefox() #调用本地的火狐浏览器,Chrom 甚至 Ie 也可以的 driver.get(url) #请求页面,会打开一个浏览器窗口 html_text=driver.page_source driver.quit() #print html_text return html_text get_text_line(get_url_dynamic2(url)) #将输出一条文本
不失为一条临时的解决方案,与selenium类似的框架还有一个windmill,
感觉稍复杂一些,这里就暂且不赘述了。
4解析JS
我们爬虫每次只有一个请求,但是实际上很多请求又js连带发送,所以我们需要利用爬虫解析js去实现这些请求的发送。
网页中的参数来源主要有以下四种:
这里主要介绍一下解析js,破解加密方法或者生成参数值方法,python代码模拟实现这个方法, 从而得到我们需要的请求参数。
以微博登录为例:
当我们点击登录的时候都会发送一个login请求
登录表单中的参数并不一定都是我们需要的,可以通过对比多次请求中的参数,再加上一些经验和猜想,过滤掉固定参数或服务器自带参数和用户输入的参数。
这是剩下的就是js生成的数值或加密数值;
最终得到的值:
# 图片 picture id:pcid: yf-d0efa944bb243bddcf11906cda5a46dee9b8# 用户名:su: cXdlcnRxd3Jlnonce: 2SSH2A # 未知# 密码:sp: e121946ac9273faf9c63bc0fdc5d1f84e563a4064af16f635000e49cbb2976d73734b0a8c65a6537e2e728cd123e6a34a7723c940dd2aea902fb9e7c6196e3a15ec52607fd02d5e5a28e18254105358e897996f0b9057afe2d24b491bb12ba29db3265aef533c1b57905bf02c0cee0c546f4294b0cf73a553aa1f7faf9f835e5prelt: 148 # 未知
请求参数中的用户名和密码都是经过加密处理的,如果需要模拟登录,就需要找到这个加密的方法,利用它来为我们的数据进行加密。
1)找到所需的js
要找到加密方法,首先我们需要先找到登录所需的js代码,可以使用以下3种方式:
① 找事件;在页面检查目标元素,在开发工具的子窗口里选中Events Listeners, 找到click事件,点击定位到js代码。
② 找请求;在Network中点击列表界面的对应Initiator跳转至对应js界面;
③ 通过搜索参数名进行定位;
2)登录的js代码
3)在这个submit的方法上打断点
然后输入用户名密码,先不点登录,回到dev tool点击这个按钮启用调试。
4)然后再去点登录按钮, 这时候就可以开始调试;
5)逐步执行代码的同时观察我们输入的参数, 发生变化的地方即为加密方法
如下示例:
6)上图中的加密方式是base64, 我们可以使用代码来试一下
import base64<br />a = "aaaaaaaaaaaa" # 输入的用户名print(base64.b64encode(a.encode())) # 得到的加密结果:b'YWFhYWFhYWFhYWFh'# 如果用户名包含@等特殊符号, 需要先用parse.quote()进行转义
得到的加密结果与网页上js的执行结果一致;
5爬虫中JS反爬技术
爬虫中遇到的js反爬技术(重点)
0 1
JS写cookie
requests请求得到的网页是一对JS,跟浏览器打开看到的网页源码完全不一样。
这种情况,往往是浏览器运行这段JS生成一个(或多个)cookie再带着这个cookie做二次请求。
在浏览器(chrome、Firefox都可以)里可以看到这一过程,首先把Chrome浏览器保存的该网站的cookie删除。
按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。
第一次打开“index.html”页面时返回的是521, 内容是一段JS代码;
第二次请求这个页面就得到了正常的HTML,查看两次请求的cookies,可以发现第二次请求时带上了一个cookie,而这个cookie并不是第一次请求时服务器发过来的,其实它就是JS生成的。
解决思路:研究那段JS,找到它生成cookie的算法,爬虫就可以解决这个问题。
0 2
JS加密ajax请求参数
抓某个网页里面的数据,发现网页源代码里面没有我们要的数据,麻烦之处在于数据往往是ajax请求得到的。
按F12打开Network窗口,刷新网页看看加载这个网页都下载了哪些URL,我们要的数据就在某个URL请求的结果里面。
这类URL在Chrome的Network里面的类型大多是XHR,通过观察它们的“Response”就可以发现我们要的数据。
我们可以把这个URL拷贝到地址栏,把那个参数随便改个字母,访问一下看看是不是能得到正确的结果,由此来验证它是否是很重要的加密参数。
解决思路:对于这样的加密参数,可以尝试通过debug JS来找到对应的JS加密算法,其中关键的是在Chrome里面设置“XHR/fetch Breakpoints”。
0 3
JS反调试(反debug)
前面我们都用到了Chrome 的F12去查看网页加载的过程,或者是调试JS的运行过程。
不过这种方法用多了,网站就加了反调试的策略,只有我们打开F12,就会暂停在一个“debugger”代码行,无论怎样都跳不出去。
不管我们点击多少次继续运行,它一直在这个“debugger”这里,每次都会多出一个VMxx的标签,观察“Call Stack”发现它好像陷入了一个函数的递归调用。
这个“debugger”让我们无法调试JS,但是关掉F12窗口,网页就正常加载了。
解决思路:“反-反调试”,通过“Call Stack”找到把我们带入死循环的函数,重新定义它。
JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。
0 4
JS发送鼠标点击事件
有些网站它的反爬都不是上面的方式,你从浏览器可以打开正常的页面,而在requests里面却被要求输入验证码或重定向其它网页。
可以试着从“Network”看看,比如下面这个Network流里面的信息:
认真看看后会发现,每点击页面的的链接,它都会做一个“cl.gif”的请求,它看上去是下载一个gif图片,然而并不是。
它请求时发送的参数非常多,而且这些参数都是当前页面的信息。比如包含了被点击的链接等等。
先来顺一下它的逻辑:
① JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。
② 服务器收到被点击链接的请求,会看看之前是不是已经通过cl.gif把对应信息发过来,如果发过来了就认为是合法的浏览器访问,给出正常的网页内容。
③ 因为requests没有鼠标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
解决思路:在访问链接前先访问一下cl.gif即可,关键是要研究cl.gif后的参数,把这些参数都带上问题就不大了,这样就可以绕过这个反爬策略。
END
最后:
欢迎关注「Python新手快速入门」
每天5分钟,学习一个Python小Tip!助力你成为更优秀的Python学习者~
javascriptscrapy工具来抓取网页内容的解决办法(一)——ajax抓取
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-06-06 20:01
ajax抓取网页内容是一个非常经典的技术,解决的问题也非常的广泛。开发一个工具来抓取站点的内容,不仅速度快,还能去除站点上的广告数据,对于抓取用户体验来说非常好。而且,如果抓取的速度不够快,那么这个工具在服务器上就要多连接几次,这种情况就会带来性能问题。因此有大神发明了javascriptscrapy工具来抓取网页内容,那么这个javascriptscrapy工具具体是干嘛的呢?今天我就给大家演示一下。
安装javascriptscrapy工具直接复制官方地址:-scrapy/scrapy-docs就可以直接进行安装。但是这样会出现一个问题,网站使用正则表达式处理,因此ip限制是必须要写在配置文件的。解决办法在配置文件中直接添加这条路径,可以满足80%的要求。此外,利用正则表达式还可以处理一些中文文本。
特别的是,javascript在python中也能使用,但是使用起来会有点吃力。我们可以通过如下方式来解决python和javascript中文处理的问题。解决办法目前最好的是使用python来处理,因为javascript提供了正则表达式api,并且在正则表达式的参数中写入python代码,就可以调用正则表达式了。
这里建议大家考虑使用python2的正则表达式库genesis-enhance-re,但是,这个库的中文处理速度慢,需要自己进行编译。不过相信日后genesis-enhance-re会与python3版本兼容,性能会有所提升。我们实际上是抓取一条ajax文本内容,在抓取结束的时候返回json格式数据。
如果速度够快,可以将字符串拼接方式切分一下,然后保存到本地。ajax抓取需要下载python,pip要安装,所以可以运行如下命令安装:pip3installjson_format-python-win32-pip6#pipinstallformat2-python-win32-pip6#pipinstallpython-win32-pip6default_as_pythonx.py,它会自动把python代码和json转换成json文件:pythonformat2.py>json_format.json编译json文件:pythonpython./python./json_format.json提取python中的所有对象:pythonobj_dict.py>json_format.json如果需要用python的doc编写正则表达式,可以通过正则表达式形式和参数形式一起来抓取,这里在编译的时候在python.py脚本的末尾添加了这样的正则表达式形式的代码:importreconst_value='{"disable_format":false,"comments":["","","",""],"overwrite":true}'有了这些特性,利用正则表达式不仅能轻松抓取网。 查看全部
javascriptscrapy工具来抓取网页内容的解决办法(一)——ajax抓取
ajax抓取网页内容是一个非常经典的技术,解决的问题也非常的广泛。开发一个工具来抓取站点的内容,不仅速度快,还能去除站点上的广告数据,对于抓取用户体验来说非常好。而且,如果抓取的速度不够快,那么这个工具在服务器上就要多连接几次,这种情况就会带来性能问题。因此有大神发明了javascriptscrapy工具来抓取网页内容,那么这个javascriptscrapy工具具体是干嘛的呢?今天我就给大家演示一下。
安装javascriptscrapy工具直接复制官方地址:-scrapy/scrapy-docs就可以直接进行安装。但是这样会出现一个问题,网站使用正则表达式处理,因此ip限制是必须要写在配置文件的。解决办法在配置文件中直接添加这条路径,可以满足80%的要求。此外,利用正则表达式还可以处理一些中文文本。
特别的是,javascript在python中也能使用,但是使用起来会有点吃力。我们可以通过如下方式来解决python和javascript中文处理的问题。解决办法目前最好的是使用python来处理,因为javascript提供了正则表达式api,并且在正则表达式的参数中写入python代码,就可以调用正则表达式了。
这里建议大家考虑使用python2的正则表达式库genesis-enhance-re,但是,这个库的中文处理速度慢,需要自己进行编译。不过相信日后genesis-enhance-re会与python3版本兼容,性能会有所提升。我们实际上是抓取一条ajax文本内容,在抓取结束的时候返回json格式数据。
如果速度够快,可以将字符串拼接方式切分一下,然后保存到本地。ajax抓取需要下载python,pip要安装,所以可以运行如下命令安装:pip3installjson_format-python-win32-pip6#pipinstallformat2-python-win32-pip6#pipinstallpython-win32-pip6default_as_pythonx.py,它会自动把python代码和json转换成json文件:pythonformat2.py>json_format.json编译json文件:pythonpython./python./json_format.json提取python中的所有对象:pythonobj_dict.py>json_format.json如果需要用python的doc编写正则表达式,可以通过正则表达式形式和参数形式一起来抓取,这里在编译的时候在python.py脚本的末尾添加了这样的正则表达式形式的代码:importreconst_value='{"disable_format":false,"comments":["","","",""],"overwrite":true}'有了这些特性,利用正则表达式不仅能轻松抓取网。
ajax解析最基础的方法是使用起来太麻烦,三步完成
网站优化 • 优采云 发表了文章 • 0 个评论 • 90 次浏览 • 2022-05-31 19:02
ajax抓取网页内容,这种技术已经应用于大量的项目中,但依然存在很多局限性。这些局限性,就是使用起来太麻烦。如果用简单的方法,可以三步完成抓取。ajax抓取效率太低目前的ajax技术,还无法把页面中所有内容完全抓取下来。有一些可以达到完全抓取的效果,但其实还不够完美。比如最近我在做的一个项目。会定期做一些数据的补充,以及增加一些普通方法无法抓取到的网页内容。
效率太低,那就降低要求,使用最基础的方法也能达到完整抓取。ajax抓取长链接容易导致页面被劫持当页面内容存在于网络中时,往往会以很多小块数据来存储。常见的就是转发,多条链接用一个url,其中转发的url长度不超过页面宽度(这里就需要用一些解析库解析长链接了)。那么有可能一个页面中会存在几十甚至上百条转发数据。
如果把所有的数据全部抓取下来,就会导致页面被刷新,页面中的所有数据全部被覆盖了。这无论是对于爬虫来说,还是对于我们来说,都不是一个好的爬虫方案。这种方法抓取的数据会有一定的局限性,比如:①数据抓取的结果有可能出现被泄露②时常可能存在页面被劫持的情况③静态资源在抓取的同时可能也会被读取③静态资源有时候会被加密,保存在自己服务器上,可能会被劫持要实现完整抓取,在手头又没有强大的开发工具支持时,只能考虑自己动手实现了。
ajax解析最基础的方法就是使用正则表达式对网页进行扫描。正则表达式可以解析的内容实在太多,这里我会简单介绍一下ajax常用的正则表达式:正则表达式={a:{c:1,d:3}}\d{2,4}\d{3,5}\d{4,5}\d{5,6}\d{6,8}\d{7,9}\d{10,11}\d{12,12}\d{13,14}然后是元素的name或tagname的匹配,包括每个元素的属性元素,name下属元素的属性,tagname下属元素的属性等。
在使用正则表达式匹配的同时,每一个元素下的属性也要一并匹配到。以上分析的是每个元素下的属性,那么像每个元素分类别的内容怎么办呢?这就要借助javascript解析javascript语法。像这样的一些文字,有些可以用let()方法定义为变量,有些可以用var()定义成函数。没有let()方法,可以用var()方法;有var()方法,可以用let()方法,但是推荐使用let()方法。
正则表达式常用的匹配方法:正则表达式匹配语法这些匹配方法的目的很明确,就是为了确定元素下的所有属性。他们很相似,但是还是有差别。不过一旦掌握了上面的方法,这些区别就可以不用关心了。let()方法最常用于匹配某个元素的属性,比如。 查看全部
ajax解析最基础的方法是使用起来太麻烦,三步完成
ajax抓取网页内容,这种技术已经应用于大量的项目中,但依然存在很多局限性。这些局限性,就是使用起来太麻烦。如果用简单的方法,可以三步完成抓取。ajax抓取效率太低目前的ajax技术,还无法把页面中所有内容完全抓取下来。有一些可以达到完全抓取的效果,但其实还不够完美。比如最近我在做的一个项目。会定期做一些数据的补充,以及增加一些普通方法无法抓取到的网页内容。
效率太低,那就降低要求,使用最基础的方法也能达到完整抓取。ajax抓取长链接容易导致页面被劫持当页面内容存在于网络中时,往往会以很多小块数据来存储。常见的就是转发,多条链接用一个url,其中转发的url长度不超过页面宽度(这里就需要用一些解析库解析长链接了)。那么有可能一个页面中会存在几十甚至上百条转发数据。
如果把所有的数据全部抓取下来,就会导致页面被刷新,页面中的所有数据全部被覆盖了。这无论是对于爬虫来说,还是对于我们来说,都不是一个好的爬虫方案。这种方法抓取的数据会有一定的局限性,比如:①数据抓取的结果有可能出现被泄露②时常可能存在页面被劫持的情况③静态资源在抓取的同时可能也会被读取③静态资源有时候会被加密,保存在自己服务器上,可能会被劫持要实现完整抓取,在手头又没有强大的开发工具支持时,只能考虑自己动手实现了。
ajax解析最基础的方法就是使用正则表达式对网页进行扫描。正则表达式可以解析的内容实在太多,这里我会简单介绍一下ajax常用的正则表达式:正则表达式={a:{c:1,d:3}}\d{2,4}\d{3,5}\d{4,5}\d{5,6}\d{6,8}\d{7,9}\d{10,11}\d{12,12}\d{13,14}然后是元素的name或tagname的匹配,包括每个元素的属性元素,name下属元素的属性,tagname下属元素的属性等。
在使用正则表达式匹配的同时,每一个元素下的属性也要一并匹配到。以上分析的是每个元素下的属性,那么像每个元素分类别的内容怎么办呢?这就要借助javascript解析javascript语法。像这样的一些文字,有些可以用let()方法定义为变量,有些可以用var()定义成函数。没有let()方法,可以用var()方法;有var()方法,可以用let()方法,但是推荐使用let()方法。
正则表达式常用的匹配方法:正则表达式匹配语法这些匹配方法的目的很明确,就是为了确定元素下的所有属性。他们很相似,但是还是有差别。不过一旦掌握了上面的方法,这些区别就可以不用关心了。let()方法最常用于匹配某个元素的属性,比如。
Python数据抓取(1) —数据处理前的准备
网站优化 • 优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-05-23 23:19
(一)数据抓取概要
如何将非结构化的数据转化为结构化的数据呢?
(二)抓取的逻辑—ETL
ETL是什么?
(三)数据抓取前的准备1.“网络爬虫”架构
网络爬虫构架
2、如何理解“网络爬虫”架构
对量化投资策略进行研究,第一步就是获取我们需要的数据,在工作实践中,比较实用的数据源就是新浪财经的数据,下面我们以新浪财经为例,为大家梳理下网络爬虫的构架
3、以抓取一个网页的内容为目的,如何去观察一个网页
我们有新浪财经的股票博客信息,我们该如何把这些信息,包含标题和时间抓取出来?
(1)使用开发人员工具观察
(2)观察Requests的构成
通常来讲,文章和新闻会放在Doc下,接下来我们要抓取的链接就藏在106个链接中的某个链接; 查看全部
Python数据抓取(1) —数据处理前的准备
(一)数据抓取概要
如何将非结构化的数据转化为结构化的数据呢?
(二)抓取的逻辑—ETL
ETL是什么?
(三)数据抓取前的准备1.“网络爬虫”架构
网络爬虫构架
2、如何理解“网络爬虫”架构
对量化投资策略进行研究,第一步就是获取我们需要的数据,在工作实践中,比较实用的数据源就是新浪财经的数据,下面我们以新浪财经为例,为大家梳理下网络爬虫的构架
3、以抓取一个网页的内容为目的,如何去观察一个网页
我们有新浪财经的股票博客信息,我们该如何把这些信息,包含标题和时间抓取出来?
(1)使用开发人员工具观察
(2)观察Requests的构成
通常来讲,文章和新闻会放在Doc下,接下来我们要抓取的链接就藏在106个链接中的某个链接;
springboot案例实战手写高效率ajax应用开发。(图)
网站优化 • 优采云 发表了文章 • 0 个评论 • 71 次浏览 • 2022-05-18 06:00
ajax抓取网页内容。首先需要明确一个问题,ajax本身并不是一个技术。只不过ajax能够让网页实现动态更新。那么我们抓取网页内容时,通常会使用一些相关技术,比如flashjavascriptjavascript,cookie等等。具体可以参考如下帖子。springboot案例实战手写高效率ajax应用开发。
一般来说抓取网页源代码一般是先抓取html源代码,再抓取js和css文件。ajax可以让服务器在一个应用内同时处理请求和更新,比如动态加载、刷新等。
我用的是activex标签。把上面图片提取出来。然后发送到postman调用处理。
一、ajax不是应用技术,而是指一种xmlhttprequest对象的特性:异步(同步请求失败后即返回非null)、无连接(在请求和响应过程中都没有包含任何连接)、幂等(在请求和响应过程中,不重复发送和接收数据),幂等是ajax的重要特性,它可以将xml数据从一个主线程传送到另一个主线程。这是ajax的核心思想,值得注意的是ajax使用的非常广泛,尤其是java、php、python等语言。
因此ajax是运用范围最广的一种应用技术。ajax相比于传统的http请求,ajax是一种应用层的技术,它在接收到响应结果的时候,已经不需要再加载其他的页面内容。大多数用php写的服务器端代码,可以把php的ajax方法封装在内置对象中供内置浏览器使用,比如preljs,同时还可以传递参数,比如request.xmlhttprequest(),request.xmlcrypt(),这样的技术就叫做定制ajax,比如postman,也可以按需定制ajax方法,例如springactivex,qqactivex接口等等。
二、ajax模式的两种实现方式:ajax本质上是通过javascript作为服务器传递数据的方式,首先创建xmlhttprequest对象,然后利用xmlhttprequest对象实现http请求,一般传递数据的话,都是传递带有token的数据,如果token不明确,就用accept-to-string解决,也就是服务器自己去请求数据,很多情况下,网页代码都是使用xmlhttprequest对象去渲染,因此服务器端都会提供额外的方法,也就是jsonp协议,在jsonp协议中,参数或者跳转的数据是不会返回到浏览器的,而是直接解析数据,然后再发送给浏览器,可以理解为post请求,但是http协议规定是只能以tcp方式连接,所以只能通过socket协议传输,即tcp。
首先注意一点,用于连接数据的ajax请求不存在浏览器回调方法,其实这个协议理论上只有一个post请求,主要是w3c一直不建议使用浏览器中的回调机制。而用于接收数据的则有cookie和urlstring方法。 查看全部
springboot案例实战手写高效率ajax应用开发。(图)
ajax抓取网页内容。首先需要明确一个问题,ajax本身并不是一个技术。只不过ajax能够让网页实现动态更新。那么我们抓取网页内容时,通常会使用一些相关技术,比如flashjavascriptjavascript,cookie等等。具体可以参考如下帖子。springboot案例实战手写高效率ajax应用开发。
一般来说抓取网页源代码一般是先抓取html源代码,再抓取js和css文件。ajax可以让服务器在一个应用内同时处理请求和更新,比如动态加载、刷新等。
我用的是activex标签。把上面图片提取出来。然后发送到postman调用处理。
一、ajax不是应用技术,而是指一种xmlhttprequest对象的特性:异步(同步请求失败后即返回非null)、无连接(在请求和响应过程中都没有包含任何连接)、幂等(在请求和响应过程中,不重复发送和接收数据),幂等是ajax的重要特性,它可以将xml数据从一个主线程传送到另一个主线程。这是ajax的核心思想,值得注意的是ajax使用的非常广泛,尤其是java、php、python等语言。
因此ajax是运用范围最广的一种应用技术。ajax相比于传统的http请求,ajax是一种应用层的技术,它在接收到响应结果的时候,已经不需要再加载其他的页面内容。大多数用php写的服务器端代码,可以把php的ajax方法封装在内置对象中供内置浏览器使用,比如preljs,同时还可以传递参数,比如request.xmlhttprequest(),request.xmlcrypt(),这样的技术就叫做定制ajax,比如postman,也可以按需定制ajax方法,例如springactivex,qqactivex接口等等。
二、ajax模式的两种实现方式:ajax本质上是通过javascript作为服务器传递数据的方式,首先创建xmlhttprequest对象,然后利用xmlhttprequest对象实现http请求,一般传递数据的话,都是传递带有token的数据,如果token不明确,就用accept-to-string解决,也就是服务器自己去请求数据,很多情况下,网页代码都是使用xmlhttprequest对象去渲染,因此服务器端都会提供额外的方法,也就是jsonp协议,在jsonp协议中,参数或者跳转的数据是不会返回到浏览器的,而是直接解析数据,然后再发送给浏览器,可以理解为post请求,但是http协议规定是只能以tcp方式连接,所以只能通过socket协议传输,即tcp。
首先注意一点,用于连接数据的ajax请求不存在浏览器回调方法,其实这个协议理论上只有一个post请求,主要是w3c一直不建议使用浏览器中的回调机制。而用于接收数据的则有cookie和urlstring方法。
百度收录网站的要求是什么?
网站优化 • 优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-05-08 23:18
做好网站排名之前最为关键的因素就是解决网站的收录问题。针对百度,它占据了绝大的搜索引擎市场份额,可谓说一家独大。那百度收录网站的要求是什么呢?
提到百度收录的网站的要求,最开始我不得不说的就是搜索引擎爬虫的抓取。如果搜索引擎爬虫不能抓取你的网站,或者爬虫无法识别网页内容的话,那百度几乎不会收录你的网站了。
爬虫抓取的可识别性
在爬虫抓取网页时,如果根本不知道你的网页内容是什么,那基本上是不会被百度收录的。所以让爬虫识别到我们网页的内容也是较为关键的一个问题。
1、robots协议的封禁
robots是一个txt文件,放置于网站的根目录下。可以通过进行访问打开。如果你的robots文件封禁了百度爬虫,那么收录简直是不可能的。
因为robots协议文件是搜索引擎与网站之间的协议文件。是网站告知搜索引擎爬虫,哪些内容你可以抓取,哪些内容你是不可以抓取。所以你都告诉爬虫不让它抓取了,他还怎么会抓取呢?
2、影响网站收录的ajax技术
js的ajax技术,其实很多做SEO的都知道不能使用js,但这并不完全是。因为爬虫抓取的是网页源代码,只要你源代码中有这些内容就是可以的。但通过js实现异步加载的内容就不行了。
这里解释一下什么是异步加载,就是当前网页源代码没有的内容。通过触发网页某个事件,js通过ajax技术动态加载出来的内容。例如典型的瀑布流网页,当你鼠标滚动到最底部,然后地步就会出现更多新的内容。多数是采用这个ajax技术。
那被异步加载出来的内容爬虫是看不到的。
3、图片、导航、ALT
图片类型的导航,现在基本很少见了。但这里还是要说一下,如果你的导航(主导航)使用图片,在这个寸土寸金的位置上,搜索引擎根本不知道你说了什么,所以这时候需要我们使用alt标签进行设置。
alt严格来说是img标签的一个属性值,是在当图片加载失败时的提示文字。如下图示例:
如上图,当图片的链接是错误时,红框中出现的就是下面源代码中alt的内容。
当然了,alt属性并不单单可以应用在图片导航中。所有你认为重要的图片,都可以进行设置,并合理的融入关键词。像一些素材图片就可以不用设置alt属性了。
4、网站访问速度慢
如果你的网站打开速度很慢的话,也会很大程度上的影响收录。我们举个例子,爬虫每天抓取你网站就给10分钟时间,你的网站访问一次需要1秒钟,和需要100毫秒。这完全是两个层次上的结果。
内容质量对收录的影响 查看全部
百度收录网站的要求是什么?
做好网站排名之前最为关键的因素就是解决网站的收录问题。针对百度,它占据了绝大的搜索引擎市场份额,可谓说一家独大。那百度收录网站的要求是什么呢?
提到百度收录的网站的要求,最开始我不得不说的就是搜索引擎爬虫的抓取。如果搜索引擎爬虫不能抓取你的网站,或者爬虫无法识别网页内容的话,那百度几乎不会收录你的网站了。
爬虫抓取的可识别性
在爬虫抓取网页时,如果根本不知道你的网页内容是什么,那基本上是不会被百度收录的。所以让爬虫识别到我们网页的内容也是较为关键的一个问题。
1、robots协议的封禁
robots是一个txt文件,放置于网站的根目录下。可以通过进行访问打开。如果你的robots文件封禁了百度爬虫,那么收录简直是不可能的。
因为robots协议文件是搜索引擎与网站之间的协议文件。是网站告知搜索引擎爬虫,哪些内容你可以抓取,哪些内容你是不可以抓取。所以你都告诉爬虫不让它抓取了,他还怎么会抓取呢?
2、影响网站收录的ajax技术
js的ajax技术,其实很多做SEO的都知道不能使用js,但这并不完全是。因为爬虫抓取的是网页源代码,只要你源代码中有这些内容就是可以的。但通过js实现异步加载的内容就不行了。
这里解释一下什么是异步加载,就是当前网页源代码没有的内容。通过触发网页某个事件,js通过ajax技术动态加载出来的内容。例如典型的瀑布流网页,当你鼠标滚动到最底部,然后地步就会出现更多新的内容。多数是采用这个ajax技术。
那被异步加载出来的内容爬虫是看不到的。
3、图片、导航、ALT
图片类型的导航,现在基本很少见了。但这里还是要说一下,如果你的导航(主导航)使用图片,在这个寸土寸金的位置上,搜索引擎根本不知道你说了什么,所以这时候需要我们使用alt标签进行设置。
alt严格来说是img标签的一个属性值,是在当图片加载失败时的提示文字。如下图示例:
如上图,当图片的链接是错误时,红框中出现的就是下面源代码中alt的内容。
当然了,alt属性并不单单可以应用在图片导航中。所有你认为重要的图片,都可以进行设置,并合理的融入关键词。像一些素材图片就可以不用设置alt属性了。
4、网站访问速度慢
如果你的网站打开速度很慢的话,也会很大程度上的影响收录。我们举个例子,爬虫每天抓取你网站就给10分钟时间,你的网站访问一次需要1秒钟,和需要100毫秒。这完全是两个层次上的结果。
内容质量对收录的影响
Python入门网络爬虫之精华版
网站优化 • 优采云 发表了文章 • 0 个评论 • 89 次浏览 • 2022-05-08 23:18
来源:宁哥的小站»Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储。
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = requests.get(url).content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = urllib2.urlopen(url).read()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Httplib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import httplib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> http = httplib2.Http()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response_headers, content = http.request(url, 'GET')<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response_headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, params=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> full_url = url+'?'+data<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(full_url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.post(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import requests <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />requests_session = requests.session() <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response = requests_session.post(url=url_login, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">response_captcha = requests_session.get(url=url_login, cookies=cookies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response1 = requests.get(url_login) # 未登陆<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, proxies=proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> proxy_support = urllib2.ProxyHandler(proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import time<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />time.sleep(1)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
4. 对于断线重连
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_session(session, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return session.post(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
或者
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_open(opener, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return opener.open(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">禁止所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: BadBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: GoodBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
学习Python和网络爬虫 查看全部
Python入门网络爬虫之精华版
来源:宁哥的小站»Python入门网络爬虫之精华版
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储。
另外,比较常用的爬虫框架Scrapy,这里最后也详细介绍一下。
首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:宁哥的小站-网络爬虫
当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入,你就会看到宁哥的小站首页。
简单来说这段过程发生了以下四个步骤:
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
抓取
这一步,你要明确要得到的内容是什么?是HTML源码,还是Json格式的字符串等。
1. 最基本的抓取
抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,requests也是非常有用的包,与此类似的,还有httplib2等等。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = requests.get(url).content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> content = urllib2.urlopen(url).read()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response.headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Httplib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import httplib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> http = httplib2.Http()<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response_headers, content = http.request(url, 'GET')<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "response headers:", response_headers<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print "content:", content<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, params=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> full_url = url+'?'+data<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(full_url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2. 对于登陆情况的处理
2.1 使用表单登陆
这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">data = {'data1':'XXXXX', 'data2':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:data为dict,json<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.post(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:data为string<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> data = urllib.urlencode(data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
2.2 使用cookie登陆
使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import requests <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />requests_session = requests.session() <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response = requests_session.post(url=url_login, data=data)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">response_captcha = requests_session.get(url=url_login, cookies=cookies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response1 = requests.get(url_login) # 未登陆<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3. 对于反爬虫机制的处理
3.1 使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">proxies = {'http':'http://XX.XX.XX.XX:XXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import requests<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, proxies=proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib2<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> proxy_support = urllib2.ProxyHandler(proxies)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(url)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.2 时间设置
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">import time<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />time.sleep(1)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
3.3 伪装成浏览器,或者反“反盗链”
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Requests:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = requests.get(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Urllib2:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> import urllib, urllib2 <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> req = urllib2.Request(url=url, headers=headers)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> response = urllib2.urlopen(req)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
4. 对于断线重连
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_session(session, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return session.post(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
或者
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">def multi_open(opener, *arg):<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes = 20<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> while retryTimes>0:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> try:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> return opener.open(*arg)<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> except:<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> print '.',<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> retryTimes -= 1<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
5. 多进程抓取
6. 对于Ajax请求的处理
它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
7. 自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
这里列出在给定城市列表后,使用selenium来动态抓取去哪儿网的票价信息的代码。
8. 验证码识别
对于网站有验证码的情况,我们有三种办法:
可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。当然也可以将验证码图片上传到打码平台上进行识别。如果不成功,可以再次更新验证码识别,直到成功为止。
爬取有两个需要注意的问题:
分析
抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
常见的分析工具有正则表达式,BeautifulSoup,lxml等等。
存储
分析出我们需要的内容之后,接下来就是存储了。
我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
存储有两个需要注意的问题:
Scrapy
Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
Robots协议
好的网络爬虫,首先需要遵守Robots协议。Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
在网站根目录下放一个robots.txt文本文件(如 ),里面可以指定不同的网络爬虫能访问的页面和禁止访问的页面,指定的页面由正则表达式表示。网络爬虫在采集这个网站之前,首先获取到这个robots.txt文本文件,然后解析到其中的规则,然后根据规则来采集网站的数据。
1. Robots协议规则
2. Robots协议举例
<p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background-color: rgb(40, 43, 46);text-indent: 0em;box-sizing: border-box !important;word-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">禁止所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许所有机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: BadBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />允许特定机器人访问<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: GoodBot<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定目录<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /images/<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />禁止访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />仅允许访问特定文件<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> User-agent: *<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Allow: /*.html$<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> Disallow: /<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /></p>
学习Python和网络爬虫
R语言爬虫系列4|AJAX与动态网页介绍
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-05-08 02:01
作者:鲁伟,热爱数据,坚信数据技术和代码改变世界。R语言和Python的忠实拥趸,为成为一名未来的数据科学家而奋斗终生。个人公众号:数据科学家养成记 (微信ID:louwill12)
第一篇戳:
第二篇戳:
第三篇戳:
很早之前就写过用rvest包实现对静态网页的抓取之类的文章,以至于很久之后看到那些文章的朋友还拿来套,以为换个网址也能达到同样的抓取效果。然而事与愿违,殊不知这些通常自己会“动”,明明是同一个url,前后硬是两个不同的网页内容,利用rvest的爬虫自然也就失效了。
究其缘由,还是在于有些网页的HTML/HTTP基础架构在一个页面布局中静态地显示内容,但是如果你用R函数来解析知乎首页,咱能通过这个首页实现抓取目的吗?答案当然是不能的。因为知乎首页是一个动态网站(DHTML),具体表现就是从首页不断下拉,网页内容在不断变化但url却一直都是,或者是点击了某个地方内容也发生了变化但抬头一看地址栏,url依然没有变化。对这样的网页进行抓取哪能按照以前的简单套路来?明显是不可行的。
网络技术实现从静态到动态转变的一个关键角色是汇总于AJAX这个术语下的一组技术,所谓AJAX,全称叫做异步JavaScript和XML(Asynchronous JavaScript and XML),它是一组技术,不同的浏览器有自己的AJAX实现组件,有了AJAX技术之后,就不需要对整个网页进行刷新了,局部更新既不占用宽带又可以提高加载速度有没有,比如说刚刚的知乎首页,想看新内容?不断把网页下拉自动加载就好。
再举个例子:比如说你们班拍毕业照,照完之后洗出来才发现哎呀少了一个人,那怎么办呢?传统的方式就是重新把大家集合起来再拍一次,那AJAX就不会这么做了,AJAX会把这位漏掉的同学P到先前的合照中去。总之,AJAX可以在不重新加载整个网页的情况下对网页的局部进行更新的某种技术。
JavaScript如何将HTML网页转化为DHTML?
JavaScript号称最流行的Web编程脚本语言,可惜小编并不懂这门语言,但这不妨碍咱们的网络数据抓取的需要。在爬虫专栏开始的第一篇文章的时候小编就说过,HTML、CSS和JavaScript是前端技术的三驾马车,要认识原生的JavaScript,重要的是了解其对于HTML的三种改进方法:
1.以HTML中的 查看全部
R语言爬虫系列4|AJAX与动态网页介绍
作者:鲁伟,热爱数据,坚信数据技术和代码改变世界。R语言和Python的忠实拥趸,为成为一名未来的数据科学家而奋斗终生。个人公众号:数据科学家养成记 (微信ID:louwill12)
第一篇戳:
第二篇戳:
第三篇戳:
很早之前就写过用rvest包实现对静态网页的抓取之类的文章,以至于很久之后看到那些文章的朋友还拿来套,以为换个网址也能达到同样的抓取效果。然而事与愿违,殊不知这些通常自己会“动”,明明是同一个url,前后硬是两个不同的网页内容,利用rvest的爬虫自然也就失效了。
究其缘由,还是在于有些网页的HTML/HTTP基础架构在一个页面布局中静态地显示内容,但是如果你用R函数来解析知乎首页,咱能通过这个首页实现抓取目的吗?答案当然是不能的。因为知乎首页是一个动态网站(DHTML),具体表现就是从首页不断下拉,网页内容在不断变化但url却一直都是,或者是点击了某个地方内容也发生了变化但抬头一看地址栏,url依然没有变化。对这样的网页进行抓取哪能按照以前的简单套路来?明显是不可行的。
网络技术实现从静态到动态转变的一个关键角色是汇总于AJAX这个术语下的一组技术,所谓AJAX,全称叫做异步JavaScript和XML(Asynchronous JavaScript and XML),它是一组技术,不同的浏览器有自己的AJAX实现组件,有了AJAX技术之后,就不需要对整个网页进行刷新了,局部更新既不占用宽带又可以提高加载速度有没有,比如说刚刚的知乎首页,想看新内容?不断把网页下拉自动加载就好。
再举个例子:比如说你们班拍毕业照,照完之后洗出来才发现哎呀少了一个人,那怎么办呢?传统的方式就是重新把大家集合起来再拍一次,那AJAX就不会这么做了,AJAX会把这位漏掉的同学P到先前的合照中去。总之,AJAX可以在不重新加载整个网页的情况下对网页的局部进行更新的某种技术。
JavaScript如何将HTML网页转化为DHTML?
JavaScript号称最流行的Web编程脚本语言,可惜小编并不懂这门语言,但这不妨碍咱们的网络数据抓取的需要。在爬虫专栏开始的第一篇文章的时候小编就说过,HTML、CSS和JavaScript是前端技术的三驾马车,要认识原生的JavaScript,重要的是了解其对于HTML的三种改进方法:
1.以HTML中的
【免费毕设】基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+lunw
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-05-08 01:32
点击上方蓝字关注我吧!
4.2 数据库的设计
本课题包含一张用于存放抓取回来的网页信息如表1。
表1 网页数据存储表
4.3 模块设计
该模型按照功能划分为三个部分,一是爬虫抓取网页部分,二是从数据库建立索引部分,三是从前台页面查询部分。系统的功能流程(如图5.1和5.2)。
该系统用3个模块来实现搜索引擎的主要功能。流程如上图所示。
从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。这条件可以是限定的某个域名空间、或者是限定的网页抓取级数。当在获取URL时存在这样的问题就是在实际应用中主要以绝对地址和相对地址来表现。绝对地址是指一个准确的、无歧义的Internet资源的位置,包含域名(主机名)、路径名和文件名;相对地址是绝对地址的一部分。然后把抓取到的网页信息包括网页内容、标题、链接抓取时间等信息经过‘减肥’后保存到网页存储数据库表里。然后通过正则表达式,去掉多余的HTML标签。因为抓取的网页含有HTML标签、Javascript等,对搜索多余的信息,如果抓取到的网页不经过处理就会使搜索变得不够精确。
让爬虫程序能继续运行下去,就得抓取这个网页上的其它URL,所以要用正则将这个网页上的所有URL都取出来放到一个队列里。用同样的方法继续抓取网页,这里将运用到多线程技术。
为了对文档进行索引,Lucene提供了五个基础的类,他们分别是Document,Field,IndexWriter,Analyzer,Directory Document是用来描述文档的,这里的文档可以指一个HTML页面,一封电子邮件,或者是一个文本文件。一个Document对象由多个Field对象组成的。可以把一个Document对象想象成数据库中的一个记录,而每个Field对象就是记录的一个字段。在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由Analyzer来做的。Analyzer类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的Analyzer。Analyzer把分词后的内容交给IndexWriter来建立索引。
论文目录:
END
联系我
获取更多资源
学习更上一层楼 查看全部
【免费毕设】基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+lunw
点击上方蓝字关注我吧!
4.2 数据库的设计
本课题包含一张用于存放抓取回来的网页信息如表1。
表1 网页数据存储表
4.3 模块设计
该模型按照功能划分为三个部分,一是爬虫抓取网页部分,二是从数据库建立索引部分,三是从前台页面查询部分。系统的功能流程(如图5.1和5.2)。
该系统用3个模块来实现搜索引擎的主要功能。流程如上图所示。
从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。这条件可以是限定的某个域名空间、或者是限定的网页抓取级数。当在获取URL时存在这样的问题就是在实际应用中主要以绝对地址和相对地址来表现。绝对地址是指一个准确的、无歧义的Internet资源的位置,包含域名(主机名)、路径名和文件名;相对地址是绝对地址的一部分。然后把抓取到的网页信息包括网页内容、标题、链接抓取时间等信息经过‘减肥’后保存到网页存储数据库表里。然后通过正则表达式,去掉多余的HTML标签。因为抓取的网页含有HTML标签、Javascript等,对搜索多余的信息,如果抓取到的网页不经过处理就会使搜索变得不够精确。
让爬虫程序能继续运行下去,就得抓取这个网页上的其它URL,所以要用正则将这个网页上的所有URL都取出来放到一个队列里。用同样的方法继续抓取网页,这里将运用到多线程技术。
为了对文档进行索引,Lucene提供了五个基础的类,他们分别是Document,Field,IndexWriter,Analyzer,Directory Document是用来描述文档的,这里的文档可以指一个HTML页面,一封电子邮件,或者是一个文本文件。一个Document对象由多个Field对象组成的。可以把一个Document对象想象成数据库中的一个记录,而每个Field对象就是记录的一个字段。在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由Analyzer来做的。Analyzer类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的Analyzer。Analyzer把分词后的内容交给IndexWriter来建立索引。
论文目录:
END
联系我
获取更多资源
学习更上一层楼
pyspider 爬虫教程 (2):AJAX 和 HTTP
网站优化 • 优采云 发表了文章 • 0 个评论 • 66 次浏览 • 2022-05-07 07:05
编译:足兆叉虫,英文:pyspider
/a/77870
在上一篇教程《》中,我们使用 self.crawl API 抓取豆瓣电影的 HTML 内容,并使用 CSS 选择器解析了一些内容。不过,现在的网站通过使用 AJAX 等技术,在你与服务器交互的同时,不用重新加载整个页面。但是,这些交互手段,让抓取变得稍微难了一些:你会发现,这些网页在抓回来后,和浏览器中的并不相同。你需要的信息并不在返回 HTML 代码中。
在这一篇教程中,我们会讨论这些技术 和 抓取他们的方法。
AJAX
AJAX 是 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)的缩写。AJAX 通过使用原有的 web 标准组件,实现了在不重新加载整个页面的情况下,与服务器进行数据交互。例如在新浪微博中,你可以展开一条微博的评论,而不需要重新加载,或者打开一个新的页面。但是这些内容并不是一开始就在页面中的(这样页面就太大了),而是在你点击的时候被加载进来的。这就导致了你抓取这个页面的时候,并不能获得这些评论信息(因为你没有『展开』)。
AJAX 的一种常见用法是使用 AJAX 加载 JSON 数据,然后在浏览器端渲染。如果能直接抓取到 JSON 数据,会比 HTML 更容易解析。
当一个网站使用了 AJAX 的时候,除了用 pyspider 抓取到的页面和浏览器看到的不同以外。你在浏览器中打开这样的页面,或者点击『展开』的时候,常常会看到『加载中』或者类似的图标/动画。例如,当你尝试抓取:
你会发现电影是『载入中…』
找到真实的请求
由于 AJAX 实际上也是通过 HTTP 传输数据的,所以我们可以通过 Chrome Developer Tools 找到真实的请求,直接发起真实请求的抓取就可以获得数据了。
打开一个新窗口
按 Ctrl+Shift+I (在 Mac 上请按 Cmd+Opt+I) 打开开发者工具。
切换到网络( Netwotk 面板)
在窗口中打开
在页面加载的过程中,你会在面板中看到所有的资源请求。
AJAX 一般是通过 XMLHttpRequest 对象接口发送请求的,XMLHttpRequest 一般被缩写为 XHR。点击网络面板上漏斗形的过滤按钮,过滤出 XHR 请求。挨个查看每个请求,通过访问路径和预览,找到包含信息的请求:%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
在豆瓣这个例子中,XHR 请求并不多,可以挨个查看来确认。但在 XHR 请求较多的时候,可能需要结合触发动作的时间,请求的路径等信息帮助在大量的请求中找到包含信息的关键请求。这需要抓取或者前端的相关经验。所以,有一个我一直在提的观点,学习抓取的最好方法是:学会写网站。
现在可以在新窗口中打开 %E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0,你会看到包含电影数据的 JSON 原始数据。推荐安装 JSONView(Firfox版)插件,这样可以看到更好看的 JSON 格式,展开折叠列等功能。然后,我们根据 JSON 数据,编写一个提取电影名和评分的脚本:
classHandler(BaseHandler):
def on_start(self):
self.crawl('',
callback=self.json_parser)
def json_parser(self,response):
return[{
"title":x['title'],
"rate":x['rate'],
"url":x['url']
}forxinresponse.json['subjects']]
你可以使用 response.json 将结果转为一个 python 的 dict 对象
你可以在 获得完整的代码,并进行调试。脚本中还有一个使用 PhantomJS 渲染的提取版本,将会在下一篇教程中介绍。 查看全部
pyspider 爬虫教程 (2):AJAX 和 HTTP
编译:足兆叉虫,英文:pyspider
/a/77870
在上一篇教程《》中,我们使用 self.crawl API 抓取豆瓣电影的 HTML 内容,并使用 CSS 选择器解析了一些内容。不过,现在的网站通过使用 AJAX 等技术,在你与服务器交互的同时,不用重新加载整个页面。但是,这些交互手段,让抓取变得稍微难了一些:你会发现,这些网页在抓回来后,和浏览器中的并不相同。你需要的信息并不在返回 HTML 代码中。
在这一篇教程中,我们会讨论这些技术 和 抓取他们的方法。
AJAX
AJAX 是 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)的缩写。AJAX 通过使用原有的 web 标准组件,实现了在不重新加载整个页面的情况下,与服务器进行数据交互。例如在新浪微博中,你可以展开一条微博的评论,而不需要重新加载,或者打开一个新的页面。但是这些内容并不是一开始就在页面中的(这样页面就太大了),而是在你点击的时候被加载进来的。这就导致了你抓取这个页面的时候,并不能获得这些评论信息(因为你没有『展开』)。
AJAX 的一种常见用法是使用 AJAX 加载 JSON 数据,然后在浏览器端渲染。如果能直接抓取到 JSON 数据,会比 HTML 更容易解析。
当一个网站使用了 AJAX 的时候,除了用 pyspider 抓取到的页面和浏览器看到的不同以外。你在浏览器中打开这样的页面,或者点击『展开』的时候,常常会看到『加载中』或者类似的图标/动画。例如,当你尝试抓取:
你会发现电影是『载入中…』
找到真实的请求
由于 AJAX 实际上也是通过 HTTP 传输数据的,所以我们可以通过 Chrome Developer Tools 找到真实的请求,直接发起真实请求的抓取就可以获得数据了。
打开一个新窗口
按 Ctrl+Shift+I (在 Mac 上请按 Cmd+Opt+I) 打开开发者工具。
切换到网络( Netwotk 面板)
在窗口中打开
在页面加载的过程中,你会在面板中看到所有的资源请求。
AJAX 一般是通过 XMLHttpRequest 对象接口发送请求的,XMLHttpRequest 一般被缩写为 XHR。点击网络面板上漏斗形的过滤按钮,过滤出 XHR 请求。挨个查看每个请求,通过访问路径和预览,找到包含信息的请求:%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
在豆瓣这个例子中,XHR 请求并不多,可以挨个查看来确认。但在 XHR 请求较多的时候,可能需要结合触发动作的时间,请求的路径等信息帮助在大量的请求中找到包含信息的关键请求。这需要抓取或者前端的相关经验。所以,有一个我一直在提的观点,学习抓取的最好方法是:学会写网站。
现在可以在新窗口中打开 %E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0,你会看到包含电影数据的 JSON 原始数据。推荐安装 JSONView(Firfox版)插件,这样可以看到更好看的 JSON 格式,展开折叠列等功能。然后,我们根据 JSON 数据,编写一个提取电影名和评分的脚本:
classHandler(BaseHandler):
def on_start(self):
self.crawl('',
callback=self.json_parser)
def json_parser(self,response):
return[{
"title":x['title'],
"rate":x['rate'],
"url":x['url']
}forxinresponse.json['subjects']]
你可以使用 response.json 将结果转为一个 python 的 dict 对象
你可以在 获得完整的代码,并进行调试。脚本中还有一个使用 PhantomJS 渲染的提取版本,将会在下一篇教程中介绍。
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTM
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-05-07 06:16
1 引言
在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验了用xslt方式一次性提取静态网页内容并转换成xml格式。留下了一个问题:javascript管理的动态内容怎样提取?那么本文就回答这个问题。
2 提取动态内容的技术部件
在上一篇python使用xslt提取网页数据中,要提取的内容是直接从网页的source code里拿到的。但是一些Ajax动态内容是在source code找不到的,就要找合适的程序库把异步或动态加载的内容加载上来,交给本项目的提取器进行提取。
python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。selenium自己不带浏览器,可以使用第三方浏览器如Firefox,Chrome等,也可以使用headless浏览器如PhantomJS在后台执行。
3 源代码和实验过程
假如我们要抓取京东手机页面的手机名称和价格(价格在网页源码是找不到的),如下图:
第一步:
利用集搜客谋数台的直观标注功能,可以极快速度自动生成一个调试好的抓取规则,其实是一个标准的xslt程序,如下图,把生成的xslt程序拷贝到下面的程序中即可。注意:本文只是记录实验过程,实际系统中,将采用多种方式把xslt程序注入到内容提取器重。
第二步:
执行如下代码(在windows10, python3.2下测试通过,下载源代码请见文章末尾的GitHub源),请注意:xslt是一个比较长的字符串,如果删除这个字符串,代码没有几行,足以见得Python之强大。
<p style="margin-top: 5px; margin-bottom: 5px; line-height: 1.5em;">#/usr/bin/pythonfrom urllib import requestfrom lxml import etreefrom selenium import webdriverimport time# 京东手机商品页面url = "http://item.jd.com/1312640.html"# 下面的xslt是通过集搜客的谋数台图形界面自动生成的xslt_root = etree.XML("""\""")# 使用webdriver.PhantomJSbrowser = webdriver.PhantomJS(executable_path='C:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')browser.get(url)time.sleep(3)transform = etree.XSLT(xslt_root)# 执行js得到整个domhtml = browser.execute_script("return document.documentElement.outerHTML")doc = etree.HTML(html)# 用xslt从dom中提取需要的字段result_tree = transform(doc)print(result_tree)<br /></p>
第三步:
下图可以看到,网页中的手机名称和价格被正确抓取下来了
End.
作者:fullerhua(中国统计网特邀认证作者)
本文为中国统计网原创文章,需要转载请联系中国统计网( ),转载时请注明作者及出处,并保留本文链接。
更多精彩,长按下方图片中的二维码,下载APP查看。
查看全部
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTM
1 引言
在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验了用xslt方式一次性提取静态网页内容并转换成xml格式。留下了一个问题:javascript管理的动态内容怎样提取?那么本文就回答这个问题。
2 提取动态内容的技术部件
在上一篇python使用xslt提取网页数据中,要提取的内容是直接从网页的source code里拿到的。但是一些Ajax动态内容是在source code找不到的,就要找合适的程序库把异步或动态加载的内容加载上来,交给本项目的提取器进行提取。
python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。selenium自己不带浏览器,可以使用第三方浏览器如Firefox,Chrome等,也可以使用headless浏览器如PhantomJS在后台执行。
3 源代码和实验过程
假如我们要抓取京东手机页面的手机名称和价格(价格在网页源码是找不到的),如下图:
第一步:
利用集搜客谋数台的直观标注功能,可以极快速度自动生成一个调试好的抓取规则,其实是一个标准的xslt程序,如下图,把生成的xslt程序拷贝到下面的程序中即可。注意:本文只是记录实验过程,实际系统中,将采用多种方式把xslt程序注入到内容提取器重。
第二步:
执行如下代码(在windows10, python3.2下测试通过,下载源代码请见文章末尾的GitHub源),请注意:xslt是一个比较长的字符串,如果删除这个字符串,代码没有几行,足以见得Python之强大。
<p style="margin-top: 5px; margin-bottom: 5px; line-height: 1.5em;">#/usr/bin/pythonfrom urllib import requestfrom lxml import etreefrom selenium import webdriverimport time# 京东手机商品页面url = "http://item.jd.com/1312640.html"# 下面的xslt是通过集搜客的谋数台图形界面自动生成的xslt_root = etree.XML("""\""")# 使用webdriver.PhantomJSbrowser = webdriver.PhantomJS(executable_path='C:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')browser.get(url)time.sleep(3)transform = etree.XSLT(xslt_root)# 执行js得到整个domhtml = browser.execute_script("return document.documentElement.outerHTML")doc = etree.HTML(html)# 用xslt从dom中提取需要的字段result_tree = transform(doc)print(result_tree)<br /></p>
第三步:
下图可以看到,网页中的手机名称和价格被正确抓取下来了
End.
作者:fullerhua(中国统计网特邀认证作者)
本文为中国统计网原创文章,需要转载请联系中国统计网( ),转载时请注明作者及出处,并保留本文链接。
更多精彩,长按下方图片中的二维码,下载APP查看。
使用Python抓取同花顺资金流数据
网站优化 • 优采云 发表了文章 • 0 个评论 • 161 次浏览 • 2022-05-06 22:22
今天我们通过一个例子来介绍python爬取数据的一般步骤,用到的工具包括python的经典模块requests和BeautifulSoup,另外结合刚学习的任务流工具TaskFlow来完成代码开发。
我们先来看一下要爬取的数据,网址是,通过chrome的开发者工具分析我们可以比较容易找到后台数据加载网址为
{page_num}/ajax/1/free/1/
其中page_num的位置为要查询第几页的数据,在网页上看到概念一共有6页数据,所以page_num取值为1-6
图示1
这里有个小技巧,可以先点击图示1左上角的清空按钮,把已经加载的网址先清理掉,然后在原始网页上点第二页,就能看到图片左下角新加载的网址,点开右边“Preview” 看到资金流数据相关的内容,就能确定这个网址是用来加载数据的。
在chrome浏览器中输入 ,并打开chrome开发者工具,在网页源码中找到数据所在table标签为
<br /> ...<br /><br />
抓取数据的完整源码如下
import time<br /><br />import requests<br />from bs4 import BeautifulSoup<br />from taskflow import engines<br />from taskflow.patterns import linear_flow<br />from taskflow.task import Task<br /><br />REQUEST_HEADER = {<br /> 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}<br /><br /><br />class MoneyFlowDownload(Task):<br /> """<br /> 下载资金流数据<br /> 数据源地址:http://data.10jqka.com.cn/funds/gnzjl/<br /><br /> """<br /> BASE_URl = {<br /> "concept": 'http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/%s/ajax/1/free/1/',<br /> }<br /><br /> def execute(self, bizdate, *args, **kwargs):<br /><br /> for name, base_url in self.BASE_URl.items():<br /> # 爬取数据的存储路径<br /> dt_path = '/data/%s_%s.csv' % (bizdate, name)<br /><br /> with open(dt_path, "a+") as f:<br /> # 记录数据文件的当前位置<br /> pos = f.tell()<br /> f.seek(0)<br /> lines = f.readlines()<br /> # 读取文件中的全部数据并将第一列存储下来作为去重依据,防止爬虫意外中断后重启程序时,重复写入相同<br /> crawled_list = list(map(lambda line: line.split(",")[0], lines))<br /> f.seek(pos)<br /> # 循环500次,从第一页开始爬取数据,当页面没有数据时终端退出循环<br /> for i in range(1, 500):<br /> print("start crawl %s, %s" % (name, base_url % i))<br /> web_source = requests.get(base_url % i, headers=REQUEST_HEADER)<br /> soup = BeautifulSoup(web_source.content.decode("gbk"), 'lxml')<br /> table = soup.select('.J-ajax-table')[0]<br /> tbody = table.select('tbody tr')<br /> # 当tbody为空时,则说明当前页已经没有数据了,此时终止循环<br /> if len(tbody) == 0:<br /> break<br /> for tr in tbody:<br /> fields = tr.select('td')<br /> # 将每行记录第一列去掉,第一列为序号,没有存储必要<br /> record = [field.text.strip() for field in fields[1:]]<br /> # 如果记录还没有写入文件中,则执行写入操作,否则跳过这行写入<br /> if record[0] not in crawled_list:<br /> f.writelines([','.join(record) + '\n'])<br /> # 同花顺网站有反爬虫的机制,爬取速度过快很可能被封<br /> time.sleep(1)<br /><br /><br />if __name__ == '__main__':<br /> bizdate = '20200214'<br /> tasks = [<br /> MoneyFlowDownload('moneyflow data download')<br /> ]<br /> flow = linear_flow.Flow('ths data download').add(*tasks)<br /> e = engines.load(flow, store={'bizdate': bizdate})<br /> e.run()<br />
执行程序后,在dt_path位置已经存储了概念的资金流数据,文件名为20200214_concept.csv,内容大致如下:
钛白粉,1008.88,6.29%,7.68,6.21,1.47,7,金浦钛业,10.04%,2.96<br />磷化工,916.833,2.42%,37.53,34.78,2.75,28,六国化工,9.97%,4.08<br />光刻胶,1435.68,2.40%,43.51,44.31,-0.80,20,晶瑞股份,10.01%,42.99<br />
此时就完成了同花顺概念分类的资金流数据的爬取,之后可以每天定时启动任务抓取数据进行分析。 查看全部
使用Python抓取同花顺资金流数据
今天我们通过一个例子来介绍python爬取数据的一般步骤,用到的工具包括python的经典模块requests和BeautifulSoup,另外结合刚学习的任务流工具TaskFlow来完成代码开发。
我们先来看一下要爬取的数据,网址是,通过chrome的开发者工具分析我们可以比较容易找到后台数据加载网址为
{page_num}/ajax/1/free/1/
其中page_num的位置为要查询第几页的数据,在网页上看到概念一共有6页数据,所以page_num取值为1-6
图示1
这里有个小技巧,可以先点击图示1左上角的清空按钮,把已经加载的网址先清理掉,然后在原始网页上点第二页,就能看到图片左下角新加载的网址,点开右边“Preview” 看到资金流数据相关的内容,就能确定这个网址是用来加载数据的。
在chrome浏览器中输入 ,并打开chrome开发者工具,在网页源码中找到数据所在table标签为
<br /> ...<br /><br />
抓取数据的完整源码如下
import time<br /><br />import requests<br />from bs4 import BeautifulSoup<br />from taskflow import engines<br />from taskflow.patterns import linear_flow<br />from taskflow.task import Task<br /><br />REQUEST_HEADER = {<br /> 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}<br /><br /><br />class MoneyFlowDownload(Task):<br /> """<br /> 下载资金流数据<br /> 数据源地址:http://data.10jqka.com.cn/funds/gnzjl/<br /><br /> """<br /> BASE_URl = {<br /> "concept": 'http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/%s/ajax/1/free/1/',<br /> }<br /><br /> def execute(self, bizdate, *args, **kwargs):<br /><br /> for name, base_url in self.BASE_URl.items():<br /> # 爬取数据的存储路径<br /> dt_path = '/data/%s_%s.csv' % (bizdate, name)<br /><br /> with open(dt_path, "a+") as f:<br /> # 记录数据文件的当前位置<br /> pos = f.tell()<br /> f.seek(0)<br /> lines = f.readlines()<br /> # 读取文件中的全部数据并将第一列存储下来作为去重依据,防止爬虫意外中断后重启程序时,重复写入相同<br /> crawled_list = list(map(lambda line: line.split(",")[0], lines))<br /> f.seek(pos)<br /> # 循环500次,从第一页开始爬取数据,当页面没有数据时终端退出循环<br /> for i in range(1, 500):<br /> print("start crawl %s, %s" % (name, base_url % i))<br /> web_source = requests.get(base_url % i, headers=REQUEST_HEADER)<br /> soup = BeautifulSoup(web_source.content.decode("gbk"), 'lxml')<br /> table = soup.select('.J-ajax-table')[0]<br /> tbody = table.select('tbody tr')<br /> # 当tbody为空时,则说明当前页已经没有数据了,此时终止循环<br /> if len(tbody) == 0:<br /> break<br /> for tr in tbody:<br /> fields = tr.select('td')<br /> # 将每行记录第一列去掉,第一列为序号,没有存储必要<br /> record = [field.text.strip() for field in fields[1:]]<br /> # 如果记录还没有写入文件中,则执行写入操作,否则跳过这行写入<br /> if record[0] not in crawled_list:<br /> f.writelines([','.join(record) + '\n'])<br /> # 同花顺网站有反爬虫的机制,爬取速度过快很可能被封<br /> time.sleep(1)<br /><br /><br />if __name__ == '__main__':<br /> bizdate = '20200214'<br /> tasks = [<br /> MoneyFlowDownload('moneyflow data download')<br /> ]<br /> flow = linear_flow.Flow('ths data download').add(*tasks)<br /> e = engines.load(flow, store={'bizdate': bizdate})<br /> e.run()<br />
执行程序后,在dt_path位置已经存储了概念的资金流数据,文件名为20200214_concept.csv,内容大致如下:
钛白粉,1008.88,6.29%,7.68,6.21,1.47,7,金浦钛业,10.04%,2.96<br />磷化工,916.833,2.42%,37.53,34.78,2.75,28,六国化工,9.97%,4.08<br />光刻胶,1435.68,2.40%,43.51,44.31,-0.80,20,晶瑞股份,10.01%,42.99<br />
此时就完成了同花顺概念分类的资金流数据的爬取,之后可以每天定时启动任务抓取数据进行分析。
Google是如何抓取JavaScript 的?
网站优化 • 优采云 发表了文章 • 0 个评论 • 54 次浏览 • 2022-05-05 21:00
导语
Google 不能处理 JavaScript ?Audette Audette 分享了一系列测试结果,看看什么类型的 JavaScript 功能会被 Google 抓取和收录吧!
1. 我们进行了一系列测试,已证实 Google 能以多种方式执行和收录 JavaScript。我们也确认 Google 能渲染整个页面并读取 DOM,由此能收录动态生成的内容。
2. DOM 中的 SEO 信号(页面标题、meta 描述、canonical 标签、meta robots 标签等)都被关注到。动态插入 DOM 的内容都也能被抓取和收录。此外,在某些案例中,DOM 甚至可能比 HTML 源码语句更优先。虽然这需要做更多的工作,但这是我们好几个测试中的一个。
Google 执行 JavaScript & 读取 DOM
早在 2008 年, Google 就 成功抓取 JavaScript,但很可能局限于某种方式。
而在今天,可以明确的是,Google 不仅能制定出他们抓取和收录的 JavaScript 类型,而且在渲染整个 web 页面上取得了显著进步(特别在最近的 12 到 18 个月)。
在 Merkle,我们的 SEO 技术团队想更好地理解谷歌爬虫能抓取和收录什么类型的 JavaSscript 事件。经过研究,我们发现令人瞠目的结果,并已证实 Google 不仅能执行各种 JavaScript 事件,而且能收录动态生成的内容。怎么样做到的?Google 能读取 DOM。
DOM 是什么?
很多搞 SEO 的都不理解什么是 Document Object Model(DOM)。
当浏览器请求页面时会发生什么,而 DOM 又是如何参与进来的。
当用于 web 浏览器,DOM 本质上是一个应用程序的接口,或 API,用于标记和构造数据(如 HTML 和 XML)。该接口允许 web 浏览器将它们进行组合而构成文档。
DOM 也定义了如何对结构进行获取和操作。虽然 DOM 是与语言无关的 API (不是捆绑在特定编程语言或库),但它普遍应用于 web 应用程序的 JavaScript 和 动态内容。
DOM 代表了接口,或“桥梁”,将 web 页面与编程语言连接起来。解析 HTML 和执行 JavaScript 的结果就是 DOM。web 页面的内容不(不仅)是源码,是 DOM。这使它变得非常重要。
我们兴奋地发现 Google 能够读取 DOM,并能解析信号和动态插入的内容,例如 title 标签、页面文本、head 标签和 meta 注解(如:rel = canonical)。可阅读其中的完整细节。
因为想知道什么样的 JavaScript 功能会被抓取和收录,我们单独对 谷歌爬虫 创建一系列测试。通过创建控件,确保 URL 活动能被独立理解。下面,让我们详细划分出一些有趣的测试结果。它们被分为 5 类:
JavaScript 重定向
JavaScript 链接
动态插入内容
动态插入 Meta 数据 和页面元素
一个带有 rel = “nofollow” 的重要例子
例子:一个用来测试谷歌爬虫理解 JavaScript 能力的页面。
1.JavaScript 重定向
我们首先测试了常见的 JavaScript 重定向,用不同方式表示的 URL 会有什么样结果呢?我们选择了 window.location 对象进行两个测试:Test A 以绝对路径 URL 调用 window.location,而 Test B 使用相对路径。
结果:该重定向很快被 Google 跟踪。从收录来看,它们被解释为 301 - 最终状态的 URL 取代了 Google 收录里的重定向 URL。
在随后的测试中,我们在一个权威网页上,利用完全相同的内容,完成一次利用 JavaScript 重定向到同一个站点的新页面。而原始 URL 是排在 Google 热门查询的首页。
结果:果然,重定向被 Google 跟踪,而原始页面并没有被收录。而新 URL 被收录了,并立刻排在相同查询页面内的相同位置。这让我们很惊喜,以排名的角度上看,视乎表明了JavaScript 重定向行为(有时)很像永久性的 301 重定向。
下次,你的客户想要为他们的网站完成 JavaScript 重定向移动,你可能不需要回答,或回答:“请不要”。因为这似乎有一个转让排名信号的关系。支持这一结论是引用了 Google 指南:
使用 JavaScript 为用户进行重定向,可能是一个合法的做法。例如,如果你将已登录用户重定向到一个内部页面,你可以使用 JavaScript 完成这一操作。当仔细检查 JavaScript 或其他重定向方法时,以确保你的站点遵循我们的指南,并考虑到其意图。记住 301 重定向跳转到你网站下是最好的,但如果你没有权限访问你网站服务器,你可以为此使用 JavaScript 重定向。
2.JavaScript 链接
我们用多种编码方式测试了不同类型的 JS 链接。
我们测试下拉菜单的链接。历史上的搜素引擎一直不能跟踪这类型的链接。我们想确定 onchange 事件处理器是否会被跟踪。重要的是,这只是执行特定的类型,而我们需要是:其它改动后的影响,而不像上面 JavaScript 重定向的强制操作。
例子: Google Work 页面的语言选择下拉菜单。
结果:链接被完整地抓取和跟踪。
我们也测试了常见的 JavaScript 链接。下面是最常见类型的 JavaScript 链接,而传统的 SEO 则推荐纯文本。这些测试包括 JavaScript 链接代码:
·作用于外部 href 键-值对(AVP),但在一个标签内(“onClick”)
·作用 href 内部 AVP(“javascript : window.location”)
·作用于 a 标签外部,但在 href 内调用 AVP(“javascript : openlink()”)
·其它
结果:链接被完整抓取和跟踪。
我们下一个测试是更进一步地测试事件处理器,如上面测试的 onchange。具体地说,我们希望利用鼠标移动的事件处理器,然后隐藏 URL 变量 ,该变量只在事件处理函数(在该案例是 onmousedown 和 onmouseout)被触发时执行。
结果:链接被完整抓取和跟踪。
构造链接:我们知道 Google 能执行 JavaScript,但想确认它们是否能读取代码里的变量。所以在该测试中,我们连接能构造 URL 字符串的字符。
结果:链接被完整抓取和跟踪。
3.动态插入内容
很明显,这些都是重点:动态插入文本、图像、链接和导航。优质的文本内容对搜索引擎理解网页主题和内容是至关重要的。在这个动态网站的时代,它的重要性是无需质疑的。
这些测试,设计出来是为了检查在两个不同场景下动态插入文本的结果。
1. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码内的。
2. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码外的(在一个外部 JavaScript 文件内)。
结果:在两个案例中,文本都能被抓取和收录,并且页面是根据该内容进行排名。爽!
为了了解更多相关信息,我们测试了一个通过 JavaScript 编写的客户端全局导航,而导航里的链接都是通过 document.writeIn 函数插入,并且确定它们能被完全抓取和跟踪。应该指出的是:Google 能解释使用 AngularJS 框架 和 HTML5 History API(pushState)构建的网站,能渲染和收录它,并能像传统静态网页一样排名。这就是 不禁止谷歌爬虫 获取外部文件和 JavaScript 的重要性,而且这也许是 Google 正在从 《支持 Ajax 的 SEO 指南》 中移除它的原因。当你能简单地渲染整个页面时候,谁还需要 HTML 快照呢?
经过测试后发现,不管什么类型的内容,都是同样的结果。例如,图像加载到 DOM 后会被抓取和收录。我们甚至做了这样的一个测试:通过动态生成 结构数据来制作 breadcrumb(面包屑导航),并将其插入 DOM。结果呢? 成功插入后的面包屑出现在搜索结果中了 (search engine results page)。
值得注意的是,Google 现在 推荐用 JSON-LD 标记 形成结构化数据。我敢肯定将来会出现更多基于此的东西。
4.动态插入 Meta 数据 & 页面元素
我们将各种对 SEO 至关重要的标签动态插入到 DOM:
Title 元素
Meta 描述
Meta robots
Canonical tags
结果:在所有案例中,标签都能被抓取,其表现就像 HTML 源码里的元素一样。
一个有趣的补充实验帮助我们理解优先顺序。当存在冲突信号时,哪一个会胜出呢?如果源码里有 noindex、nofollow 标签,而 DOM 里有 noindex、follow 标签的话,将会发生什么呢?在这协议里,HTTP x-robots 响应头部的行为如何作为另一个变量?这将是未来综合测试的一部分。然而,我们的测试显示:当冲突时,Google 会无视源码里的标签,而支持 DOM。
1.一个带有 rel =“nofollow” 的重要例子
我们想测试 Google 如何应对出现在源码和 DOM 的链路级别的 nofollow 属性。我们也因此创建了一个没有应用 nofollow 的控件。
对于 nofollow ,我们分别单独测试源码 vs DOM 生成的注解。
源码里的 nofollow 正如我们所期待的那样运行(链接没被跟踪)。而 DOM 里的 nofollow 却失效(链接被跟踪,并且页面被收录)。为什么?因为在 DOM 里修改 href 元素的操作发生得太晚了:Google 在执行添加 rel=”nofollow” 的 JavaScript 函数前,已准备好抓取链接和队列等待着 URL。然而,如果将带有 href =”nofollow”的 a 元素插入到 DOM,nofollow 和链接因在同一时刻插入,所以会被跟踪。
结果
从历史角度上看,各种 SEO 推荐是在任何可能的时候,要尽可能专注 ‘纯文本’ 内容。而动态生成内容、AJAX 和 JavaScript 链接会损害主流搜索引擎的 SEO。显然,这对 Google 不再是问题。 JavaScript 链接以类似普通的 HTML 链接方式运行(这只是表面,而我们不知道幕后程序进行了什么操作)。
·JavaScript 重定向都会以类似于 301 重定向方式对待。
·动态插入内容,甚至 meta 标签,如 rel canonical 注解,无论在 HTML 源码,还是在最初 HTML 被解析后触发 JavaScript 生成 DOM ,都以同等方式对待。
·Google 视乎能完全渲染页面和理解 DOM ,而不仅是源码。实在是令人可不思议!(记得允许谷歌爬虫获取那些外部文件和 JavaScript。)
Google 已经在创新方面,以惊人的速度将其它搜索引擎甩在身后。我们希望看到其它搜索引擎能有同样类型的创新。如果他们要保持竞争力,并在 web 新时代取得实质性进展,这意味着它们要更好地支持 HTML5、JavaScript 和 动态网站。
对于 SEO,那些没有理解上述基本概念和 Google 技术的人,应该好好研究和学习,以赶上当前技术。如果你不把 DOM 考虑在内,您可能会丢失一半份额。
原文:
关于21CTO社区
是中国互联网第一技术人脉与社交平台。我们为国内最优秀的开发者提供社交、学习等产品,帮助企业快速对接开发者,包括人才招聘,项目研发,顾问咨询服务。
看微信文章不过瘾,请移步到网站,诚挚欢迎您加入社区作者团队。
网站地址:
投稿邮箱: 查看全部
Google是如何抓取JavaScript 的?
导语
Google 不能处理 JavaScript ?Audette Audette 分享了一系列测试结果,看看什么类型的 JavaScript 功能会被 Google 抓取和收录吧!
1. 我们进行了一系列测试,已证实 Google 能以多种方式执行和收录 JavaScript。我们也确认 Google 能渲染整个页面并读取 DOM,由此能收录动态生成的内容。
2. DOM 中的 SEO 信号(页面标题、meta 描述、canonical 标签、meta robots 标签等)都被关注到。动态插入 DOM 的内容都也能被抓取和收录。此外,在某些案例中,DOM 甚至可能比 HTML 源码语句更优先。虽然这需要做更多的工作,但这是我们好几个测试中的一个。
Google 执行 JavaScript & 读取 DOM
早在 2008 年, Google 就 成功抓取 JavaScript,但很可能局限于某种方式。
而在今天,可以明确的是,Google 不仅能制定出他们抓取和收录的 JavaScript 类型,而且在渲染整个 web 页面上取得了显著进步(特别在最近的 12 到 18 个月)。
在 Merkle,我们的 SEO 技术团队想更好地理解谷歌爬虫能抓取和收录什么类型的 JavaSscript 事件。经过研究,我们发现令人瞠目的结果,并已证实 Google 不仅能执行各种 JavaScript 事件,而且能收录动态生成的内容。怎么样做到的?Google 能读取 DOM。
DOM 是什么?
很多搞 SEO 的都不理解什么是 Document Object Model(DOM)。
当浏览器请求页面时会发生什么,而 DOM 又是如何参与进来的。
当用于 web 浏览器,DOM 本质上是一个应用程序的接口,或 API,用于标记和构造数据(如 HTML 和 XML)。该接口允许 web 浏览器将它们进行组合而构成文档。
DOM 也定义了如何对结构进行获取和操作。虽然 DOM 是与语言无关的 API (不是捆绑在特定编程语言或库),但它普遍应用于 web 应用程序的 JavaScript 和 动态内容。
DOM 代表了接口,或“桥梁”,将 web 页面与编程语言连接起来。解析 HTML 和执行 JavaScript 的结果就是 DOM。web 页面的内容不(不仅)是源码,是 DOM。这使它变得非常重要。
我们兴奋地发现 Google 能够读取 DOM,并能解析信号和动态插入的内容,例如 title 标签、页面文本、head 标签和 meta 注解(如:rel = canonical)。可阅读其中的完整细节。
因为想知道什么样的 JavaScript 功能会被抓取和收录,我们单独对 谷歌爬虫 创建一系列测试。通过创建控件,确保 URL 活动能被独立理解。下面,让我们详细划分出一些有趣的测试结果。它们被分为 5 类:
JavaScript 重定向
JavaScript 链接
动态插入内容
动态插入 Meta 数据 和页面元素
一个带有 rel = “nofollow” 的重要例子
例子:一个用来测试谷歌爬虫理解 JavaScript 能力的页面。
1.JavaScript 重定向
我们首先测试了常见的 JavaScript 重定向,用不同方式表示的 URL 会有什么样结果呢?我们选择了 window.location 对象进行两个测试:Test A 以绝对路径 URL 调用 window.location,而 Test B 使用相对路径。
结果:该重定向很快被 Google 跟踪。从收录来看,它们被解释为 301 - 最终状态的 URL 取代了 Google 收录里的重定向 URL。
在随后的测试中,我们在一个权威网页上,利用完全相同的内容,完成一次利用 JavaScript 重定向到同一个站点的新页面。而原始 URL 是排在 Google 热门查询的首页。
结果:果然,重定向被 Google 跟踪,而原始页面并没有被收录。而新 URL 被收录了,并立刻排在相同查询页面内的相同位置。这让我们很惊喜,以排名的角度上看,视乎表明了JavaScript 重定向行为(有时)很像永久性的 301 重定向。
下次,你的客户想要为他们的网站完成 JavaScript 重定向移动,你可能不需要回答,或回答:“请不要”。因为这似乎有一个转让排名信号的关系。支持这一结论是引用了 Google 指南:
使用 JavaScript 为用户进行重定向,可能是一个合法的做法。例如,如果你将已登录用户重定向到一个内部页面,你可以使用 JavaScript 完成这一操作。当仔细检查 JavaScript 或其他重定向方法时,以确保你的站点遵循我们的指南,并考虑到其意图。记住 301 重定向跳转到你网站下是最好的,但如果你没有权限访问你网站服务器,你可以为此使用 JavaScript 重定向。
2.JavaScript 链接
我们用多种编码方式测试了不同类型的 JS 链接。
我们测试下拉菜单的链接。历史上的搜素引擎一直不能跟踪这类型的链接。我们想确定 onchange 事件处理器是否会被跟踪。重要的是,这只是执行特定的类型,而我们需要是:其它改动后的影响,而不像上面 JavaScript 重定向的强制操作。
例子: Google Work 页面的语言选择下拉菜单。
结果:链接被完整地抓取和跟踪。
我们也测试了常见的 JavaScript 链接。下面是最常见类型的 JavaScript 链接,而传统的 SEO 则推荐纯文本。这些测试包括 JavaScript 链接代码:
·作用于外部 href 键-值对(AVP),但在一个标签内(“onClick”)
·作用 href 内部 AVP(“javascript : window.location”)
·作用于 a 标签外部,但在 href 内调用 AVP(“javascript : openlink()”)
·其它
结果:链接被完整抓取和跟踪。
我们下一个测试是更进一步地测试事件处理器,如上面测试的 onchange。具体地说,我们希望利用鼠标移动的事件处理器,然后隐藏 URL 变量 ,该变量只在事件处理函数(在该案例是 onmousedown 和 onmouseout)被触发时执行。
结果:链接被完整抓取和跟踪。
构造链接:我们知道 Google 能执行 JavaScript,但想确认它们是否能读取代码里的变量。所以在该测试中,我们连接能构造 URL 字符串的字符。
结果:链接被完整抓取和跟踪。
3.动态插入内容
很明显,这些都是重点:动态插入文本、图像、链接和导航。优质的文本内容对搜索引擎理解网页主题和内容是至关重要的。在这个动态网站的时代,它的重要性是无需质疑的。
这些测试,设计出来是为了检查在两个不同场景下动态插入文本的结果。
1. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码内的。
2. 测试搜索引擎能否统计动态插入的文本,而文本是来自页面 HTML 源码外的(在一个外部 JavaScript 文件内)。
结果:在两个案例中,文本都能被抓取和收录,并且页面是根据该内容进行排名。爽!
为了了解更多相关信息,我们测试了一个通过 JavaScript 编写的客户端全局导航,而导航里的链接都是通过 document.writeIn 函数插入,并且确定它们能被完全抓取和跟踪。应该指出的是:Google 能解释使用 AngularJS 框架 和 HTML5 History API(pushState)构建的网站,能渲染和收录它,并能像传统静态网页一样排名。这就是 不禁止谷歌爬虫 获取外部文件和 JavaScript 的重要性,而且这也许是 Google 正在从 《支持 Ajax 的 SEO 指南》 中移除它的原因。当你能简单地渲染整个页面时候,谁还需要 HTML 快照呢?
经过测试后发现,不管什么类型的内容,都是同样的结果。例如,图像加载到 DOM 后会被抓取和收录。我们甚至做了这样的一个测试:通过动态生成 结构数据来制作 breadcrumb(面包屑导航),并将其插入 DOM。结果呢? 成功插入后的面包屑出现在搜索结果中了 (search engine results page)。
值得注意的是,Google 现在 推荐用 JSON-LD 标记 形成结构化数据。我敢肯定将来会出现更多基于此的东西。
4.动态插入 Meta 数据 & 页面元素
我们将各种对 SEO 至关重要的标签动态插入到 DOM:
Title 元素
Meta 描述
Meta robots
Canonical tags
结果:在所有案例中,标签都能被抓取,其表现就像 HTML 源码里的元素一样。
一个有趣的补充实验帮助我们理解优先顺序。当存在冲突信号时,哪一个会胜出呢?如果源码里有 noindex、nofollow 标签,而 DOM 里有 noindex、follow 标签的话,将会发生什么呢?在这协议里,HTTP x-robots 响应头部的行为如何作为另一个变量?这将是未来综合测试的一部分。然而,我们的测试显示:当冲突时,Google 会无视源码里的标签,而支持 DOM。
1.一个带有 rel =“nofollow” 的重要例子
我们想测试 Google 如何应对出现在源码和 DOM 的链路级别的 nofollow 属性。我们也因此创建了一个没有应用 nofollow 的控件。
对于 nofollow ,我们分别单独测试源码 vs DOM 生成的注解。
源码里的 nofollow 正如我们所期待的那样运行(链接没被跟踪)。而 DOM 里的 nofollow 却失效(链接被跟踪,并且页面被收录)。为什么?因为在 DOM 里修改 href 元素的操作发生得太晚了:Google 在执行添加 rel=”nofollow” 的 JavaScript 函数前,已准备好抓取链接和队列等待着 URL。然而,如果将带有 href =”nofollow”的 a 元素插入到 DOM,nofollow 和链接因在同一时刻插入,所以会被跟踪。
结果
从历史角度上看,各种 SEO 推荐是在任何可能的时候,要尽可能专注 ‘纯文本’ 内容。而动态生成内容、AJAX 和 JavaScript 链接会损害主流搜索引擎的 SEO。显然,这对 Google 不再是问题。 JavaScript 链接以类似普通的 HTML 链接方式运行(这只是表面,而我们不知道幕后程序进行了什么操作)。
·JavaScript 重定向都会以类似于 301 重定向方式对待。
·动态插入内容,甚至 meta 标签,如 rel canonical 注解,无论在 HTML 源码,还是在最初 HTML 被解析后触发 JavaScript 生成 DOM ,都以同等方式对待。
·Google 视乎能完全渲染页面和理解 DOM ,而不仅是源码。实在是令人可不思议!(记得允许谷歌爬虫获取那些外部文件和 JavaScript。)
Google 已经在创新方面,以惊人的速度将其它搜索引擎甩在身后。我们希望看到其它搜索引擎能有同样类型的创新。如果他们要保持竞争力,并在 web 新时代取得实质性进展,这意味着它们要更好地支持 HTML5、JavaScript 和 动态网站。
对于 SEO,那些没有理解上述基本概念和 Google 技术的人,应该好好研究和学习,以赶上当前技术。如果你不把 DOM 考虑在内,您可能会丢失一半份额。
原文:
关于21CTO社区
是中国互联网第一技术人脉与社交平台。我们为国内最优秀的开发者提供社交、学习等产品,帮助企业快速对接开发者,包括人才招聘,项目研发,顾问咨询服务。
看微信文章不过瘾,请移步到网站,诚挚欢迎您加入社区作者团队。
网站地址:
投稿邮箱:
如何用Python抓取脉脉职言区的评论数据
网站优化 • 优采云 发表了文章 • 0 个评论 • 139 次浏览 • 2022-05-05 20:15
最近对脉脉的“职言”(之前叫匿名讨论区)感兴趣了,发现很多互联网公司的爆料都是从这里开始的,比如近期的互联网界愈演愈烈的“裁员潮”,在这里呈现井喷的趋势。
脉脉“职言”上关于“裁员”的讨论声量趋势分布,与百度指数的搜索量走势高度重合
由此,笔者决心用Python爬虫去上面抓取网友的讨论数据,以期后续能从中发掘一些有趣的insight,比如大家吐槽的热点(裁员潮、欠薪)、互联网公司的一些雷区(求职面试)以及一些经验(职业发展)...
笔者发现,在web端是可以登录脉脉的,这就方便了接下来的爬虫数据抓取工作。
脉脉“职言”页面
笔者在这里是采用搜索的方式定向获取数据,比如,我比较关心职言讨论区涉及“数据分析”的评论,看看大家在讨论“数据分析”的哪些方面的话题。
先观察下页面结构,笔者发现讨论区的评论是需要不断往下拉才能看到新内容的,所以这里使用了Ajax技术---在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化。
按下F12,依次点击“Network"-->"XHR",找到下拉加载时产生的请求数据。
发现脉脉“职言”要通过下拉方式才能获得新数据,由此确定它采用了ajax进行加载
重点关注它的请求URL和请求表单数据。
请求URL和表单数据,这是突破口
点击Response,发现里面的数据是json格式的,如下图所示:
数据是以json的形式进行呈现
首先分析该请求的url结构,从中发现规律,方便接下来构造请求链接。在这里,笔者采用Python标准库urllib中的parse库,用来解析和构造链接。
<p style="line-height: 1.5em;">from urllib.parse import urlparse,parse_qs,urlencode
url_name = urlparse(
'https://maimai.cn/search/gossips?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1')
url_name</p>
ParseResult(scheme='https', netloc='', path='/search/gossips', params='',query='query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1', fragment='')
依次得到协议类型、域名、路径、参数、请求和fragment。
将上面的query再进行解析,得到请求参数。
<p style="line-height: 1.5em;">parse_qs('query=%E8%A3%81%E5%91%98&limit=20&offset=20&searchTokens=%5B%22%E8%A3%81%E5%91%98%22%5D&highlight=true&sortby=&jsononly=1')</p>
{'query': ['裁员'], 'limit': ['20'], 'offset': ['20'], 'searchTokens': ['["裁员"]'], 'highlight': ['true'], 'jsononly': ['1']}
对于解析出来的结果,重点关注query、offset和searchTokens。其中,offset是偏移量,以20为单位进行增量,而query和searchTokens就是一回事,构造链接的时候写成一样的表达即可。
编写如下的链接构造函数。
<p style="line-height: 1.5em;">def key_word_search_url(keyword,offset):
data = {'query': keyword,
'limit': 20,
'offset': offset,
'searchTokens': keyword,
'highlight': 'true',
'jsononly': '1'}
search_url = 'https://maimai.cn/search/gossips?' + urlencode(data)
return search_url</p>
试试效果如何,以“社交媒体”为例,offset为20进行测试
<p style="line-height: 1.5em;">key_word_search_url('社交媒体',20)</p>
'%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&limit=20&offset=20&searchTokens=%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&highlight=true&jsononly=1'
将构造的链接放到浏览器中,看看能不能请求到数据。
json格式的数据,其实这种形式的数据是爬虫最喜欢的!
看来构造出来的请求链接是OK的!
好了,可以正式开始爬虫编写了!
第一步:载入必要的库,以及采用post方式进行登录。
<p style="line-height: 1.5em;">import requests
import re
import lxml.etree
import lxml.html
from urllib.parse import urlparse,parse_qs,urlencode
from tqdm import tqdm
from tkinter import _flatten
import pandas as pd
from fake_useragent import UserAgent
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from requests_futures.sessions import FuturesSession
from requests import Session
import time
import os
import random
ua = UserAgent() #随机生成用户代理
requests_session = FuturesSession(executor = ProcessPoolExecutor(max_workers=10),session=Session())
headers = {'user-agent':ua.random ,
'path':'/search/gossips?query=%E5%8F%A3%E7%A2%91&limit=20&offset=20&searchTokens=%5B%22%E5%8F%A3%E7%A2%91%22%5D&highlight=true&sortby=&jsononly=1',
'authority':'脉脉-成就职业梦想',
'referer':'https://maimai.cn/web/search_center?type=gossip&query=%E5%8F%A3%E7%A2%91&highlight=true',
'cookie':'''guid=GxIaBBsfEwQbEx4EGxgeVhkaGBMZHhpWGhoeBB0dHxgEGQQaGwVYT1ldRVhoe3sKGhoeBBwdHRwEGRwEGwVPWEVpChwZBB0ZHwVDWEtMS3kKHBgEExkYGQQaBBkcBU9HRVhCaQoDRUFJT20KT0FDRgoGZmd+YmECChwZBB0ZHwVeQ2FIT31PRlpaawoDHhx9ZX0KERoEGhsKfmQKWV1FTkRDfQIKGgQfBUtGRkNQRWc=; sessionid=yolyiy13px6c3wk1lc07c0tlmmmx2f4g; _buuid=558e1d44-6e93-4c65-8220-ecd9a4f050f5; seid=s1547559716083; token="AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="; uid="RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA="; session=eyJ1IjoiMzA3ODMxOTIiLCJzZWNyZXQiOiJyLVFPZTFhSFd2UE1fVmhhMHFZNjFWVE0iLCJfZXhwaXJlIjoxNTQ3NjQ2MTQ2OTQ0LCJfbWF4QWdlIjo4NjQwMDAwMH0=; session.sig=wrNrB1mK9WOBUNgU2ZFv7KMlGO0'''
}
data = {'u':'30783192',
'channel':'www',
'version':'4.0.0',
'_csrf':'semzdd8v-7gvL_7e0fLTVhsFMvglLykXUnuE',
'access_token':'1.c8169081785b6fd48f6a960f6719cfb8',
'uid':"RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA=",
'token':"AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="}
#response = requests.post('https://www.huxiu.com/v2_action/article_list', headers=headers,data = data)
response = requests_session.post('脉脉-成就职业梦想, headers=headers,data = data)
# 通过get请求返回的文本值
#print(response.result().text)</p>
第二步:使用代理IP进行数据爬取,防止爬虫被封。
<p style="line-height: 1.5em;">api_url = 'http://dynamic.goubanjia.com/dynamic/get/a93a315bcfae9120aee86832d3adca44.html?sep=3&random=true'
proxy_host = None
def update_proxy():
import urllib
global proxy_host
print('请求代理...')
proxy_host = urllib.request.urlopen(api_url).read().decode('utf-8').strip('\n')
print('取得代理IP:',proxy_host)</p>
第三步:编写解析函数,即获得页面的json数据。
<p style="line-height: 1.5em;">def parse_page(keyword,offset):
response_list = []
update_proxy()
proxies = {'http':proxy_host}
for i in range(0,offset,20):
response = requests_session.get(key_word_search_url(keyword,offset),
headers=headers,
proxies=proxies)
time.sleep(random.randint(2,6)) #在2秒~6秒钟随意切换数值,降低爬取频率,防止被封杀
# 通过get请求返回的文本值
response_list.append(response.result())
data = _flatten([i.json()['data']['gossips'] for i in response_list])
print(len(data))
return data </p>
第四步:将前面的函数整合到一起,提取json数据中重要的字段。
其中涉及:
<p style="line-height: 1.5em;">def main(keyword,offset):
name,text,total_cnt,likes,unlikes,crtime,id,is_freeze,search_order,encode_id= [],[],[],[],[],[],[],[],[],[]
for i in tqdm(parse_page(keyword,offset)):
name.append(i['gossip']['username']) #昵称
text.append(i['gossip']['text']) #文本
total_cnt.append(i['gossip']['total_cnt']) #评论数
likes.append(i['gossip']['likes']) #喜欢数
unlikes.append( i['gossip']['unlikes']) #讨厌数
crtime.append(i['gossip']['crtime']) #创建时间
id.append(i['gossip']['id']) #匿言ID
is_freeze.append(i['gossip']['is_freeze']) #匿言is_freeze
search_order.append(i['gossip']['search_order']) #匿言检索顺序
encode_id.append(i['gossip']['encode_id']) #匿言帖子编码
data = {'name':name,'text':text,'total_cnt':total_cnt,'likes':likes,'unlikes':unlikes,'crtime':crtime,'id':id,'is_freeze':is_freeze,'search_order':search_order,'encode_id':encode_id}
data_house = pd.DataFrame(data,columns=['name','text','total_cnt','likes','unlikes','crtime','id','is_freeze','search_order','encode_id'])
data_house = data_house.drop_duplicates("id")
data_house = data_house.sort_values(by='total_cnt',ascending=False)
data_house.to_csv('{}.csv'.format(keyword))
return data_house </p>
函数编写完成后,先提取部分数据试试。
<p style="line-height: 1.5em;">data_list = main('数据分析',60)</p>
工工整整的表格数据,做文本挖掘很适合!
看来效果不错!
有了这些数据以后,你可以做:
之前有过类似的分析,详情请参看:
苏格兰折耳喵:
苏格兰折耳喵:
苏格兰折耳喵: 查看全部
如何用Python抓取脉脉职言区的评论数据
最近对脉脉的“职言”(之前叫匿名讨论区)感兴趣了,发现很多互联网公司的爆料都是从这里开始的,比如近期的互联网界愈演愈烈的“裁员潮”,在这里呈现井喷的趋势。
脉脉“职言”上关于“裁员”的讨论声量趋势分布,与百度指数的搜索量走势高度重合
由此,笔者决心用Python爬虫去上面抓取网友的讨论数据,以期后续能从中发掘一些有趣的insight,比如大家吐槽的热点(裁员潮、欠薪)、互联网公司的一些雷区(求职面试)以及一些经验(职业发展)...
笔者发现,在web端是可以登录脉脉的,这就方便了接下来的爬虫数据抓取工作。
脉脉“职言”页面
笔者在这里是采用搜索的方式定向获取数据,比如,我比较关心职言讨论区涉及“数据分析”的评论,看看大家在讨论“数据分析”的哪些方面的话题。
先观察下页面结构,笔者发现讨论区的评论是需要不断往下拉才能看到新内容的,所以这里使用了Ajax技术---在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化。
按下F12,依次点击“Network"-->"XHR",找到下拉加载时产生的请求数据。
发现脉脉“职言”要通过下拉方式才能获得新数据,由此确定它采用了ajax进行加载
重点关注它的请求URL和请求表单数据。
请求URL和表单数据,这是突破口
点击Response,发现里面的数据是json格式的,如下图所示:
数据是以json的形式进行呈现
首先分析该请求的url结构,从中发现规律,方便接下来构造请求链接。在这里,笔者采用Python标准库urllib中的parse库,用来解析和构造链接。
<p style="line-height: 1.5em;">from urllib.parse import urlparse,parse_qs,urlencode
url_name = urlparse(
'https://maimai.cn/search/gossips?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1')
url_name</p>
ParseResult(scheme='https', netloc='', path='/search/gossips', params='',query='query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1', fragment='')
依次得到协议类型、域名、路径、参数、请求和fragment。
将上面的query再进行解析,得到请求参数。
<p style="line-height: 1.5em;">parse_qs('query=%E8%A3%81%E5%91%98&limit=20&offset=20&searchTokens=%5B%22%E8%A3%81%E5%91%98%22%5D&highlight=true&sortby=&jsononly=1')</p>
{'query': ['裁员'], 'limit': ['20'], 'offset': ['20'], 'searchTokens': ['["裁员"]'], 'highlight': ['true'], 'jsononly': ['1']}
对于解析出来的结果,重点关注query、offset和searchTokens。其中,offset是偏移量,以20为单位进行增量,而query和searchTokens就是一回事,构造链接的时候写成一样的表达即可。
编写如下的链接构造函数。
<p style="line-height: 1.5em;">def key_word_search_url(keyword,offset):
data = {'query': keyword,
'limit': 20,
'offset': offset,
'searchTokens': keyword,
'highlight': 'true',
'jsononly': '1'}
search_url = 'https://maimai.cn/search/gossips?' + urlencode(data)
return search_url</p>
试试效果如何,以“社交媒体”为例,offset为20进行测试
<p style="line-height: 1.5em;">key_word_search_url('社交媒体',20)</p>
'%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&limit=20&offset=20&searchTokens=%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&highlight=true&jsononly=1'
将构造的链接放到浏览器中,看看能不能请求到数据。
json格式的数据,其实这种形式的数据是爬虫最喜欢的!
看来构造出来的请求链接是OK的!
好了,可以正式开始爬虫编写了!
第一步:载入必要的库,以及采用post方式进行登录。
<p style="line-height: 1.5em;">import requests
import re
import lxml.etree
import lxml.html
from urllib.parse import urlparse,parse_qs,urlencode
from tqdm import tqdm
from tkinter import _flatten
import pandas as pd
from fake_useragent import UserAgent
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from requests_futures.sessions import FuturesSession
from requests import Session
import time
import os
import random
ua = UserAgent() #随机生成用户代理
requests_session = FuturesSession(executor = ProcessPoolExecutor(max_workers=10),session=Session())
headers = {'user-agent':ua.random ,
'path':'/search/gossips?query=%E5%8F%A3%E7%A2%91&limit=20&offset=20&searchTokens=%5B%22%E5%8F%A3%E7%A2%91%22%5D&highlight=true&sortby=&jsononly=1',
'authority':'脉脉-成就职业梦想',
'referer':'https://maimai.cn/web/search_center?type=gossip&query=%E5%8F%A3%E7%A2%91&highlight=true',
'cookie':'''guid=GxIaBBsfEwQbEx4EGxgeVhkaGBMZHhpWGhoeBB0dHxgEGQQaGwVYT1ldRVhoe3sKGhoeBBwdHRwEGRwEGwVPWEVpChwZBB0ZHwVDWEtMS3kKHBgEExkYGQQaBBkcBU9HRVhCaQoDRUFJT20KT0FDRgoGZmd+YmECChwZBB0ZHwVeQ2FIT31PRlpaawoDHhx9ZX0KERoEGhsKfmQKWV1FTkRDfQIKGgQfBUtGRkNQRWc=; sessionid=yolyiy13px6c3wk1lc07c0tlmmmx2f4g; _buuid=558e1d44-6e93-4c65-8220-ecd9a4f050f5; seid=s1547559716083; token="AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="; uid="RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA="; session=eyJ1IjoiMzA3ODMxOTIiLCJzZWNyZXQiOiJyLVFPZTFhSFd2UE1fVmhhMHFZNjFWVE0iLCJfZXhwaXJlIjoxNTQ3NjQ2MTQ2OTQ0LCJfbWF4QWdlIjo4NjQwMDAwMH0=; session.sig=wrNrB1mK9WOBUNgU2ZFv7KMlGO0'''
}
data = {'u':'30783192',
'channel':'www',
'version':'4.0.0',
'_csrf':'semzdd8v-7gvL_7e0fLTVhsFMvglLykXUnuE',
'access_token':'1.c8169081785b6fd48f6a960f6719cfb8',
'uid':"RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA=",
'token':"AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="}
#response = requests.post('https://www.huxiu.com/v2_action/article_list', headers=headers,data = data)
response = requests_session.post('脉脉-成就职业梦想, headers=headers,data = data)
# 通过get请求返回的文本值
#print(response.result().text)</p>
第二步:使用代理IP进行数据爬取,防止爬虫被封。
<p style="line-height: 1.5em;">api_url = 'http://dynamic.goubanjia.com/dynamic/get/a93a315bcfae9120aee86832d3adca44.html?sep=3&random=true'
proxy_host = None
def update_proxy():
import urllib
global proxy_host
print('请求代理...')
proxy_host = urllib.request.urlopen(api_url).read().decode('utf-8').strip('\n')
print('取得代理IP:',proxy_host)</p>
第三步:编写解析函数,即获得页面的json数据。
<p style="line-height: 1.5em;">def parse_page(keyword,offset):
response_list = []
update_proxy()
proxies = {'http':proxy_host}
for i in range(0,offset,20):
response = requests_session.get(key_word_search_url(keyword,offset),
headers=headers,
proxies=proxies)
time.sleep(random.randint(2,6)) #在2秒~6秒钟随意切换数值,降低爬取频率,防止被封杀
# 通过get请求返回的文本值
response_list.append(response.result())
data = _flatten([i.json()['data']['gossips'] for i in response_list])
print(len(data))
return data </p>
第四步:将前面的函数整合到一起,提取json数据中重要的字段。
其中涉及:
<p style="line-height: 1.5em;">def main(keyword,offset):
name,text,total_cnt,likes,unlikes,crtime,id,is_freeze,search_order,encode_id= [],[],[],[],[],[],[],[],[],[]
for i in tqdm(parse_page(keyword,offset)):
name.append(i['gossip']['username']) #昵称
text.append(i['gossip']['text']) #文本
total_cnt.append(i['gossip']['total_cnt']) #评论数
likes.append(i['gossip']['likes']) #喜欢数
unlikes.append( i['gossip']['unlikes']) #讨厌数
crtime.append(i['gossip']['crtime']) #创建时间
id.append(i['gossip']['id']) #匿言ID
is_freeze.append(i['gossip']['is_freeze']) #匿言is_freeze
search_order.append(i['gossip']['search_order']) #匿言检索顺序
encode_id.append(i['gossip']['encode_id']) #匿言帖子编码
data = {'name':name,'text':text,'total_cnt':total_cnt,'likes':likes,'unlikes':unlikes,'crtime':crtime,'id':id,'is_freeze':is_freeze,'search_order':search_order,'encode_id':encode_id}
data_house = pd.DataFrame(data,columns=['name','text','total_cnt','likes','unlikes','crtime','id','is_freeze','search_order','encode_id'])
data_house = data_house.drop_duplicates("id")
data_house = data_house.sort_values(by='total_cnt',ascending=False)
data_house.to_csv('{}.csv'.format(keyword))
return data_house </p>
函数编写完成后,先提取部分数据试试。
<p style="line-height: 1.5em;">data_list = main('数据分析',60)</p>
工工整整的表格数据,做文本挖掘很适合!
看来效果不错!
有了这些数据以后,你可以做:
之前有过类似的分析,详情请参看:
苏格兰折耳喵:
苏格兰折耳喵:
苏格兰折耳喵: