Python爬虫(为了迎合active,有彩蛋)


声明:只是为了参加’CSDN2023年博客之星’活动,其他人的行为与本人无关



众所周知,Python是最适合做爬虫的语言,没有之一。
关于爬虫,有很多精彩的故事,比如爬虫与反爬虫、反反爬与反反反爬,当然这篇属于基础,不会涉及到这些,也不会涉及到爬虫框架(如分布式多线程爬虫框架scrapy),也不会涉及到那些基础中的基础(如request由哪些组成、用Python写一个网络编程)

大概流程:

  • 发送请求
  • 获取响应
  • 解析数据
  • 保存

1. 发送请求

用的到模块:requests

request()方法是所有方法的基础方法,它有三个参数methodurl和一组控制访问参数**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方法
  1. 首先指定 url(也就是想要爬取的目标网址),比如说想要爬取百度

    url = 'https://www.baidu.com/'
    
  2. 可以使用代理

    proxies={
    'http':'http://127.0.0.1:8080',
    'https':'http://127.0.0.1:8080'
    }
    r = requests.get(url,proxies=proxies)
    
  3. 请求头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)
    
  4. 综合

  • 请求头一般不设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('', 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"
    }
    

用得到的模块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,最终需要安装两个:即Selenium2和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模块

保存

可以根据模块和自己的喜好存取

你可能感兴趣的:(公开,python,爬虫,开发语言)