当前位置: 首页 > 后端技术 > Python

【Python解答】爬虫爬取过程中常见小问题梳理

时间:2023-03-26 17:13:34 Python

现在写爬虫,入门不再是高门槛。网上的教程很多,但是很多新手爬虫还是遇到了这样那样的问题。今天整理了一些新手在爬取过程中遇到的问题,希望能为大家提供一些解决问题的思路和参考。01中文无法正常显示?使用requests库或urllib库获取源码时,无法正常显示中文;r=requests.get('http://xxx')printr.text在使用requests解析中文网页时,上面的语句在ipython中总是打印乱码……试过如下代码:importsysreload(sys)sys.setdefaultencoding('utf8')和类似的:r.text.decode('coding1').encoding('coding2')不能用!解决方案①requests库中有两种文本。一种是文本类型,使用text属性,另一种是针对音频、视频、图片等二进制数据类型,使用content属性。一般text属性返回时会出现中文乱码,所以返回输出前需要显示的修改属性编码,可以指定为“utf-8”或apparent_encoding。②urllib库中的文本只有一种,就是使用read()方法读取。所以,要解决中文问题,必须在读取后加上.decode("utf-8"),转码显示后就不会出现了。乱码问题。02加密问题爬虫一般是怎么解决加密问题的?①对于网页来说,加密算法一般都是用js代码写的,所以首先要懂js语言。起码知道js的基本内容,其次找到对应的js加密代码,再找出关键函数。在node.js环境中调试js代码,最后使用execjs库在Python环境中执行调试好的代码。②模拟浏览器环境直接获取渲染数据。最常见的方法是使用Selenium框架。这种方法很方便,当然相应的缺点就是效率很低。但是现在有一个新的框架来替代Selenium,就是Puppeteer,大家可以看到是Selenium的一个异步版本。对于一个爬虫程序,一个通用的公式:爬虫程序=网络请求+数据分析+数据存储这三部分对应了这个爬虫的基础,任何一个爬虫程序都会保存这三部分的内容,一些复杂的爬虫不过如此在此基础上增加一些其他内容。爬虫工程师的反爬能力再强,他的爬虫强度也一样高。03获取不到网页的所有代码?问题:通过请求方式获取的网页代码与浏览器中看到的网页源代码不一致;解决方法:由于很多网页的数据传输都是通过js命令传给网页的,所以不能使用request()方法获取js信息代码传递过来的数据。这时,通过使用selenium库模拟浏览器的操作,就像真实用户在操作一样,通过这种方法就可以得到网页的源代码。fromselenium.webdriver.support.waitimportWebDriverWaitbrowser=webdriver.Chrome()browser.get(Url)html=browser.page_source04点击下一页时,网页保持不变。问题:在爬取过程中,由于爬取了每一个律师详细信息对应的URL,所以涉及到翻页的问题,但是在网页上实时点击下一页时,发现网址没有改变。解决方法:使用selenium中的nextpagebutton.click()方法模拟跳转到下一页,从而获取下一页的内容。nextpagebutton=browser.find_element_by_xpath('//*[@class="next_page"]')#定位到“下一页”按钮nextpagebutton.click()#模拟点击下一页wait=WebDriverWait(browser,10)#BrowseServerwait10s05文本节点问题先看两段HTML代码,这是你眼中的HTML代码:这是计算机眼中的HTML代码:解决方法:在BS4中,我们看到的换行符和空格在HTML中都是NavigableString是文本节点。06如何快速找到提取的数据?解析网页时,如何快速找到数据存放的位置并提取数据?这是很多新手都会遇到的问题;也就是虽然我的代码跑起来没问题,逻辑大概也能看懂,但是想修改爬取类似的网站或者同一网站的其他数据的时候不知道从何下手。这其实是因为你不熟悉工具的使用;在这里简单介绍一下(beautifulSoup)的常用使用技巧,当然它还有很多强大方便的功能。这里只介绍几个常用的功能,这几个功能用好几乎可以搞定所有的网站。首先,在爬取之前,需要定位到数据所在的标签。在F12开发者工具中使用这个按钮,点击按钮,再点击网页,可以快速定位到页面中对应的标签。这一步我就不细说了,很简单,大家自己摸索吧。接下来介绍如何使用代码获取那个标签;首先你观察你要找的标签,是什么标签?有没有class或者id之类的属性(如果没有就找它的父标签,尽量找这样的)因为如果用class和id这两个属性作为过滤条件的话,发现的干扰项很少。运气好的话,基本上是一击必中。这里有beautifulSoup中的两个函数,find和find_all函数;例如,当我们要获取上图中箭头指向的id为ozoom的div标签时,我们可以这样做:#html为上次请求获取的网页内容bsobj=bs4.BeautifulSoup(html,'html.parser')#获取id为ozoom的div标签#根据id查找标签div=bsobj.find('div',attrs={'id':'ozoom'})#继续获取div下class为list_t的div标签#根据class查找标签title=div.find('div',attrs={'class':'list_t'})注意:如果标签有id属性,试试要使用idlookup,因为整个页面id是唯一的。如果用class来搜索,最好在浏览器的网页源代码中用Ctrl+F搜索,看看有多少个是同一个class的标签。(如果比较多,可以先尝试找到它的父标签,缩小范围再搜索)然后说说find_all函数,适合一次搜索一个类型的多个标签,比如下图的情况List中的每一个li标签都是一条数据,我们需要全部获取。如果我们使用前面的find函数,一次只能得到一个li标签。所以我们需要使用find_all函数一次获取所有符合条件的标签,将它们存储为数组并返回。由于li标签没有id和class,页面上有很多不相关和干扰的li标签,我们需要先从它的父标签往上查找,缩小查找范围。找到id为titleList的div标签后,观察里面的li标签都是需要的,可以使用find_all函数一次性获取。#html为要抓取的目标页面内容html=fetchUrl(pageUrl)bsobj=bs4.BeautifulSoup(html,'html.parser')pDiv=bsobj.find('div',attrs={'id':'titleList'})titleList=pDiv.find_all('li')基本上结合了find和find_all的功能,熟练的话几乎可以搞定所有的html网页。07获取标签中的数据找到标签后,如何获取标签中的数据呢?数据在标签中的位置一般有两种情况:

ThisisdataThisisthedata

如果是第一种情况,很简单,直接pTip.text即可;(pTip就是之前已经获取到的p标签)if第二种情况,需要看是在哪个属性中,比如我们要获取上面a标签中href属性中的链接,我们可以link=aTip["href"].(aTip是之前获取到的a标签)。08去除指定内容去除获取内容开头和结尾的指定字符串;问题:有时候在爬取的过程中,获取到的信息并非都是我们要获取的内容,如果我们要去除指定的内容。例如:stringa=["aaaa"],但只想得到中间的aaaa的字符串也将被删除remove。如果确定要获取的文本不包含符号,可以使用正则表达式。x=strTemp.xpath('./div[3]/div[1]/div/div/div[1]/div/ul/li[14]//text()')xx=str(x)电子邮件=re.search(r'[\u4e00-\u9fa5a-zA-Z0-9]+',xx)第二种方法是使用strip()方法去掉第一个和最后一个符号;a=td[1].get_text().strip('[""]')09转成string类型通过正则表达式得到的内容是match类型,如何转成stringstr类型?解决方法:使用group(0)转成string类型email=email.group(0)10滥用遍历文档树的常用方法有:contentsdescendantsparentnext_siblingnext_element这些方法会遍历文档树中的所有节点,包括文本节点。也就是说,只要使用这些方法,肯定会选中很多文本节点,因为文本节点无处不在,比如换行符、空格等。解决方法:使用filterfind等方法;soup.find(name='tagname')一旦我们在过滤器中指定了name关键字,返回的结果一定是tag对象,因为文档节点没有name属性。结论:在大多数情况下,你需要的是像find这样的过滤器,而不是遍历所有节点。11数据库存储问题在数据库存储数据的过程中,遇到的一些问题如下:1)爬取的内容是列表形式,如何将其转换成字符串类型?解决方法:使用str()方法b=strTemp.xpath('./div[3]/div[1]/div/div/div[1]/div/ul/li[3]//text()')agee=str(b)注意:数据库中对应的字段类型要和python中一致;2)python和mysql数据库连接connection=pymysql.connect(host='localhost',user='root',password='zaizaizai',db='layer',charset='utf8mb4')try:#Getsessionpointerwithconnection.cursor()ascursor:#创建SQL语句sql="insertintolayer(namee,organization,sex,age,nation,edu,leixing,zhengzhi,numberr,first_time,get_time,status,paizhu,sifaju,email)values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"#执行SQL语句cursor.execute(sql,(namee,organization,sex,age,nation,edu,leixing,zhengzhi,numberr,first_time,get_time,status,paizhu,sifaju,email))#提交connection.commit()finally:connection.close()3)文件夹中保存的图片不断被后面抓取的图片覆盖?变量放在for循环内外可能是个问题。修改后可以解决这个问题,用一些小例子来测试:#Test1x=0foriinrange(0,10):forjinrange(0,10):printxx+=1foriin范围(0,10):x=0forjinrange(0,10):printxx+=1#testtwo>>>x=0>>>foriinrange(0,10):print('iis',i)x=0forjinrange(0,10):print('thejis',j)print('thexis',x)x+=1>>>foriinrange(0,10):print('theiis',i)x=0forjinrange(0,10):print('thejis',j)print('thexis',x)x=x+112爬虫采集遇到的被墙问题主要表现为无法访问,访问几次就坏了,然后手动访问,或者换终端后,完全没有问题。我们先思考以下几个问题:爬虫是不是访问太频繁了?影响了对方服务器的业务?爬虫收集是否违反了对方的防御机制?爬虫是否存在让对方不知所措的bug?以上主观问题属于红线问题,必须考虑。一定要掌握好爬虫的规模,不能损害他人的合法权益。总结了管理员和防火墙拦截遇到的一些问题和原因;1)管理员不想让你访问,这种情况分为两种:第一种:管理员登录后台看到有个家伙10小时我刚访问我的网站10000次就不停!如果是我,第一反应就是屏蔽,肯定有问题,就不用分析了。第二种:感觉有人在爬数据,想把他找出来。2)网站配置不允许您访问此主要是网站限制;比如tomcat或者Nginx,限制某个连接的访问??时间,因为如果这个连接一直都在,然后又有新的连接进来,连接池迟早会满,最后就完了。你就是想DDOS攻击我,我可以设置你不动多久,我给你断掉。3)防火墙难配置,因为防火墙很细,如果是服务器WAF,会很头疼。它在拦截DDOS的时候,非常容易拦截爬虫。如果你想绕过WAF,那就是入侵。要从页面采集数据,只能欺骗WAF,继续刷新数据页面。4)如何规避上述策略,主要是欺骗和伪装。采用或搭建IP代理避免IP识别,更改IP地址,减少单个IP触发规则,拦截恶意IP是网站管理过程中最常用的方法。更改请求内容虽然你的IP变了,但还是原来的浏览器,或者cookie记录,会被识别。这可以通过更改cookie和标头来伪装。降低访问频率一般情况下,如果单位时间内访问网站的次数过高,很容易被判断为CC攻击。而且会给服务器造成很大压力,影响正常业务。这偏离了我们收集数据的初衷,所以设置一个sleep(),降低刷新频率,减少对服务器资源的占用。慢攻辨别慢了就被打死!慢速攻击即http慢速攻击是利用http合法机制,在连接建立后尽可能长时间保持连接不释放,从而对HTTP服务进行攻击。攻击者发送POST请求,构造消息向服务器提交数据,并将消息长度设置为较大的值。并且在后续的每次发送中,每次只发送一条小消息,导致服务器一直在等待数据,连接一直被占用。如果攻击者使用多线程或傀儡机进行同样的操作,服务器WEB容器很快就会塞满TCP连接,不再接受新的请求,从而导致服务器崩溃和服务失败。最好的办法是使用多线程异步收集,同时及时关闭之前的连接,控制数量。总之,在收集数据的时候,站在别人的角度去思考,用别人能接受的方式获取数据,这样别人才能让你妥善获取数据。这是一个双赢的行为,否则也只是从入门到入狱的过渡。每个人都不容易,他们会互相送食物。13验证码问题如何解决验证码问题?大致思路有两种:对于正向破解,比如常见的图文验证码,可以先保存图片,然后用一些图文识别图片来识别对应的内容。对于滑块验证码,可以使用Selenium框架计算出间隙的距离,然后模拟鼠标拖动滑块。反向破解涉及到验证码的实现逻辑,需要了解对方验证码的逻辑。查看发送验证码请求时需要哪些参数,以及这些参数是如何生成的,模拟请求。反向破解是一种短期省力的方法,但对应的难度非常高。->直接使用编码平台。以上两种方式都是非常耗时耗力的行为,而且对方网站的反爬策略一旦更新,你的代码就会失效。所以对于可以用钱解决的事情,大家可以选择直接使用打码平台。学习Python爬虫需要三个部分:Python基础爬虫基础反爬学习。这三部分是爬虫必备的基础。主流语言是Python,Python有非常丰富的爬虫库可以直接拿来用。方便的。想学好Python但又没有具体学习方向和路线的朋友,欢迎上gzh【Python编程学习圈】,分享大量技术干货文章和学习资料教程,回复【学习资料】获取免费的,不要错过哦~