众所周知,Python是最适合做爬虫的语言,没有之一。
关于爬虫,有很多精彩的故事,比如爬虫与反爬虫、反反爬与反反反爬,当然这篇属于基础,不会涉及到这些,也不会涉及到爬虫框架(如分布式多线程爬虫框架scrapy),也不会涉及到那些基础中的基础(如request由哪些组成、用Python写一个网络编程)
request()
方法是所有方法的基础方法,它有三个参数method
、url
和一组控制访问参数**kwargs
。其中,method
表示通过request()
实现的请求方式;url
指获取页面的url链接
;**kwargs
是13个控制访问参数。
method共
有7种请求方式,分别是GET/HEAD/POST/PUT/PATCH/delete/OPTIONS
。
前6种
是HTTP协议对应的请求功能,而OPTIONS
事实上是向服务器获取一些服务器和客户端能够打交道的参数,并不与获取资源直接相关,因此我们在平时使用中用的比较少。
在这7种请求方式
中,如果选定了一种,我们可以使用request()
直接实现,也可以用Requests
库的对应方法,当然Requests库的对应方法也是基于request(
)方法封装起来的。
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支持以下各个方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTTP网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTTP网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTTP页面提交删除请求,对应于HTTP的DELETE |
首先指定 url
(也就是想要爬取的目标网址),比如说想要爬取百度
url = 'https://www.baidu.com/'
可以使用代理
proxies={
'http':'http://127.0.0.1:8080',
'https':'http://127.0.0.1:8080'
}
r = requests.get(url,proxies=proxies)
请求头headers
fake_useragent的简单使用
from fake_useragent import UserAgent
ua=UserAgent()
print(ua.random)
headers={
'user-agent':ua.random
}
使用headers参数
设置cookie
,使用fake_useragent模块
生成随机请求头
#使用fake_useragent模块随机生成请求头
headers={'user-agent':UserAgent().random,
'cookie':'sessionid=6zogmfbqdgdgy3a4mk9h53qd1ldgdgd4nuuw8kzw4'}
请求此网站如果没有携带cookie信息,将会跳转到登录页面 (allow_redirects参数,用来控制是否重向,默认是True,由此来排除请求被重定向后到登录页面响应成功的情况)
from fake_useragent import UserAgent
headers={'user-agent':UserAgent().random,#使用 fake_useragent模块随机生成请求头
'cookie':'sessionid=6zogmfbqydgddg3a4mdgdgk9h53qd1l4nuuw8kzw4'}
response=requests.get(url='https://login2.scrape.center/',headers =headers,allow_redirects=False)#allow_redirects用来设置是否页 面跳转重定向,默认是True
print(response.status_code)
综合
请求头一般不设cookie,如果需要也会用js,其作用可不小,比如(参考链接):
请求头写的越详细,返回的数据越多,至少把fake_useragent 用上
allow_redirects用来设置是否页 面跳转重定向,默认是True(一般不设)
verify设置是否验证证书,verify参数默认是True(一般设为false)
timeout超时参数
在进行网络爬虫开发时,经常需要设置请求的超时时间,以避免请求时间过长而导致程序卡死。Python的requests库提供了设置timeout参数的方法,可以轻松实现
使用连接超时和读取超时设置超时时间
使用连接超时和读取超时可以分别设置请求的连接超时和读取超时。以下示例:
import requests
url = 'https://www.example.com/api/users'
response = requests.get(url, timeout=(3, 5))
print(response.json())
整合一下
import requests
from fake_useragent import UserAgent
headers={'user-agent':UserAgent().random}
proxies={
'http':'http://127.0.0.1:8080',
'https':'http://127.0.0.1:8080'
}
url = 'https://www.example.com/api/users'
response = requests.get(url, timeout=(3, 5), verify=False, headers=headers, proxies=proxies)
关于JS
代码(JS作为反反爬方式之一)
# import sys
import re
import requests
import execjs
from fake_useragent import UserAgent
import importlib, sys
# reload(sys)
# sys.setdefaultencoding('utf8')
importlib.reload(sys)
class YiDaiYiLuSpider(object):
"""
中国一带一路网(521反爬)
"""
USER_AGENT = UserAgent()
ua = USER_AGENT.random
url = r'https://www.yidaiyilu.gov.cn/xwzx/gnxw/87373.htm'
headers = {
"Host": "www.yidaiyilu.gov.cn",
"User-Agent": ua
}
@classmethod
def get_text521(cls):
"""
:return:
"""
rs = requests.session()
resp = rs.get(url=cls.url, headers=cls.headers)
text_521 = ''.join(re.findall('', resp.text))
cookie_id = '; '.join(['='.join(item) for item in resp.cookies.items()])
return cookie_id, text_521
@classmethod
def generate_cookies(cls, func):
"""
:param func:
:return:
"""
func_return = func.replace('eval', 'return')
content = execjs.compile(func_return)
eval_func = content.call('f')
var = str(eval_func.split('=')[0]).split(' ')[1]
rex = r">(.*?)"
rex_var = re.findall(rex, eval_func)[0]
mode_func = eval_func.replace('document.cookie=', 'return ').replace(';if((function(){try{return !!window.addEventListener;}', ''). \
replace("catch(e){return false;}})()) {document.addEventListener('DOMContentLoaded'," + var + ",false)}", ''). \
replace("else{document.attachEvent('onreadystatechange'," + var + ")}", '').\
replace(r"setTimeout('location.href=location.pathname+location.search.replace(/[\? |&]captcha-challenge/,\'\')',1500);", '').\
replace('return return', 'return').\
replace("document.createElement('div')", '"https://www.yidaiyilu.gov.cn/"').\
replace(r"{0}.innerHTML='{1}';{0}= {0}.firstChild.href;".format(var, rex_var), '')
content = execjs.compile(mode_func)
cookies_js = content.call(var)
__jsl_clearance = cookies_js.split(';')[0]
return __jsl_clearance
@classmethod
def crawler(cls):
"""
:return:
"""
url = r'https://www.yidaiyilu.gov.cn/zchj/sbwj/87255.htm'
cookie_id, text_521 = cls.get_text521()
__jsl_clearance = cls.generate_cookies(text_521)
cookies = "{0};{1};".format(cookie_id, __jsl_clearance)
cls.headers["Cookie"] = cookies
print(cls.headers)
res = requests.get(url=url, headers=cls.headers)
res.encoding = 'utf-8'
print(res.text)
if __name__ == '__main__':
YiDaiYiLuSpider.crawler()
附录
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "max-age=0",
"Connection": "keep-alive",
"Referer": "https://www.cnvd.org.cn/flaw/show/CNVD-2018-18002",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
"sec-ch-ua": "^\\^Google",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "^\\^Windows^^"
}
cookies = {
"__jsluid_s": "dd683c0967c65e19b98ed14c5feae2b6",
"__jsl_clearance_s": "1673252591.732^|0^|ISUEgGOC8T^%^2BZ436DI4YFDgq^%^2Fcnw^%^3D",
"JSESSIONID": "E503376819F8DE0563408E0419309262"
}
pip install splinter
from splinter import Browser
browser = Browser()
browser.visit('http://google.com')
browser.fill('q', 'splinter - python acceptance testing for web applications')
browser.find_by_name('btnG').click()
if browser.is_text_present('splinter.readthedocs.io'):
print "Yes, the official website was found!"
else:
print "No, it wasn't found... We need to improve our SEO techniques"
browser.quit()
splinter
访问浏览器,还需要安装对应的浏览器驱动,这里以chrome
为例,由于chrome WebDriver
依赖于Selenium2
,最终需要安装两个:即Selenium
2和chromedriver
pip install selenium
browser = Browser(driver_name='chrome', executable_path='./chromedriver')
python2有urllib和urllib2两种模块,都用来实现网络请求的发送。python3将urllib和urllib2模块整合并命名为urllib模块。
参考链接:
python爬虫urllib模块详解
python爬虫之urllib库详解
requests 将自动解码来自服务器的内容。大多数unicode字符集都是无缝解码的。
当你发出请求时,requests会根据HTTP头对响应的编码进行有依据的猜测。当你访问r.text时,将使用requests猜测的文本编码。可以使用r.encoding属性查找请求使用的编码,并对其进行更改:
>>> r.encoding # 输出:utf-8
r.encoding = 'ISO-8859-1'
如果更改编码,则每当调用r.text时,requests都将使用新的r.encoding的值。在任何情况下,你都可以应用特殊逻辑来确定内容的编码。例如,HTML和XML可以在其正文中指定其编码。在这种情况下,你应该使用r.content查找编码,然后设置r.encoding。这将允许你使用具有正确编码的r.text。
requests还将在需要时使用自定义编码。如果你已经创建了自己的编码并将其注册到codecs模块,则可以简单地使用codec名称作为r.encoding的值,而requests将为你处理解码。
对于非文本请求,还可以以字节的形式访问响应体(当然,文本请求也可以)
requests会自动解码gzip和deflate传输编码。
如果安装了类似 brotli 或 brotlicffi的Brotil类库,Requets也会自动界面br传输编码
如果Brotli库(如[Brotli])为您自动解码br传输编码(https://pypi.org/project/brotli)或brotliffi已安装。
例如,可以使用以下代码,从请求返回的二进制数据创建图像:
from PIL import Image
from io import BytesIO
img = Image.open(BytesIO(r.content))
如果JSON解码失败,r.json()将抛出异常。例如,如果响应得到一个204(无内容),或者如果响应包含无效的JSON,则r.json()会抛出requests.exceptions.JSONDecodeError。此封装的异常可能会因为不同python版本和JSON序列化库可能引发的多个异常提供互操作性。
需要注意的是,调用r.json()的成功调用并不表示响应的成功。一些服务器可能会在失败的响应中返回JSON对象(例如,HTTP 500的错误详细信息)。这样的JSON将被解码并返回。要检查请求是否成功,请使用r.raise_for_status()或检查r.status_code
可以通过访问r.raw访问服务器返回的原始socket响应。如果希望这样做,确保在初始请求中设置 stream=True:
>>> import requests
>>> r = requests.get('https://api.github.com/events', stream=True)
>>> r.raw
<urllib3.response.HTTPResponse object at 0x0000018DB1704D30>
>>> r.raw.read(10)
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
然而,通常情况下,应该使用类似这样的模式来保存正在流式传输的内容到文件中:
with open(filename, 'wb') as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
使用Response.iter_content将处理很多你在直接使用Resort.raw时需要处理的事情。当流式传输下载时,以上是检索内容的首选和推荐方法。请注意,chunk_size可以自由调整为更适合你使用场景的数字。
注意
关于使用 Response.iter_content与Response.raw的重要注意事项。 Response.iter_content将自动解码gzip和deflate传输编码。Response.raw是一个原始字节流–它不会转换响应内容。如果确实需要访问返回的字节,请使用Response.raw。
可以根据模块和自己的喜好存取