Python爬虫(为了迎合active,有彩蛋)
声明:只是为了参加’CSDN2023年博客之星’活动,其他人的行为与本人无关
众所周知,Python是最适合做爬虫的语言,没有之一。
关于爬虫,有很多精彩的故事,比如爬虫与反爬虫、反反爬与反反反爬,当然这篇属于基础,不会涉及到这些,也不会涉及到爬虫框架(如分布式多线程爬虫框架scrapy),也不会涉及到那些基础中的基础(如request由哪些组成、用Python写一个网络编程)
大概流程:
- 发送请求
- 获取响应
- 解析数据
- 保存
1. 发送请求
用的到模块:requests
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库的7个主要方法
方法 | 说明 |
---|---|
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 |
这里主要讲解get方法
-
首先指定
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,其作用可不小,比如(参考链接):
- JS写cookie
- JS加密ajax请求参数
- JS反调试(反debug)
- JS发送鼠标点击事件
-
请求头写的越详细,返回的数据越多,至少把fake_useragent 用上
-
allow_redirects用来设置是否页 面跳转重定向,默认是True(一般不设)
-
verify设置是否验证证书,verify参数默认是True(一般设为false)
- SSL 证书遵守 SSL协议,由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,具有“服务器身份验证”和“数据传输加密功能”
- 使用requests模块进行请求时默认认证ssl证书,虽然很多网站都要求使用HTTPS证书,但是有的网站并没有设置HTTPS证书或者证书失效
-
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('<script>(.*?)</script>', 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">(.*?)</a>" 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='<a href=\'/\'>{1}</a>';{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" }
用得到的模块selenium&splinter
pip install splinter
splinter链接:https://splinter.readthedocs.io/en/latest/
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
- selenium安装
pip install selenium
- 对于chromedriver
- 首先查看浏览器版本,在chrome浏览器访问:chrome://version/
- 然后访问http://chromedriver.storage.googleapis.com/index.html,找到对应的版本下载即可。
自动爬取,也是反反爬的一种,这个模块也可以作为自动测试用,内容很多不在展开
browser = Browser(driver_name='chrome', executable_path='./chromedriver')
用得到的模块urllib
python2有urllib和urllib2两种模块,都用来实现网络请求的发送。python3将urllib和urllib2模块整合并命名为urllib模块。
- urllib模块有多个子模块,各有不同的功能:
- urllib.request模块:用于实现基本的http请求。
- urllib.error模块:用于异常处理。如在发送网络请求时出现错误,用该模块捕捉并处理。
- urllib.parse模块:用于解析。
- urllib.robotparser:用于解析robots.txt文件,判断是否可以爬取网站信息。
- python爬虫主要用到的urllib库中的request和parse模块
参考链接:
python爬虫urllib模块详解
python爬虫之urllib库详解
2. 获取响应
响应内容
文本内容:r.text
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将为你处理解码。
二进制非文本内容:r.content
对于非文本请求,还可以以字节的形式访问响应体(当然,文本请求也可以)
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
如果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
可以通过访问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。
解析数据
lxml模块
BeautifulSoup
xml模块
numpy模块
pandas模块
保存
可以根据模块和自己的喜好存取
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)