您现在的位置是:网站首页> 编程资料编程资料

python爬虫抓取时常见的小问题总结_python_

2023-05-26 263人已围观

简介 python爬虫抓取时常见的小问题总结_python_

前言:

现在写爬虫,入门已经不是一件门槛很高的事情了,网上教程一大把,但很多爬虫新手在爬取数据的过程中依旧会遇到这样那样的问题。

今天整理了部分新手在爬虫过程中遇到的问题,希望可以给大家提供一点问题解决的思路和参考。

01 无法正常显示中文?

使用requests库或者urllib库获取源代码时无法正常显示中文;

r = requests.get('http://xxx')print r.text

使用requests解析中文网页时,上述语句在ipython中一直打印的都是乱码.......

试过如下代码:

import sys reload(sys) sys.setdefaultencoding('utf8') 

还有类似:

r.text.decode('coding1').encoding('coding2')

都不能凑效!

解决方法

① requests库的文本中有两种类型

  • 一种是文本类型,使用text属性,一种是针对音频、视频、图片等二进制数据类型,使用content属性。
  • 一般返回的是text属性时会出现中文乱码现象,因此在输出返回之前需要显示的修改属性encoding,将其赋值为“utf-8”或者是apparent_encoding即可。

② urllib库的文本只有一种就是使用read()方法进行读取

因此要解决中文问题,一定要在读取后加入.decode(“utf-8”),进行显示的转码之后便不会出现乱码问题了。

02 加密问题 

爬虫一般怎么解决加密问题?

① 对于网页端来说通常加密的算法是写在 js 代码里的,所以首先你要对 js 语言有所了解。

至少知道 js 基础的内容,其次找到对应 js 加密代码,然后找出关键的函数。

把 js 代码在 node.js 环境进行调试,最后在 Python 环境下利用 execjs 库去执行调试好的代码。

② 就是模拟浏览器环境直接获取渲染后的数据,最常用的手段就是利用 Selenium 框架了。

这种方式非常便利,当然对应的缺点就是效率非常低下。不过现在有新的框架来取代 Selenium,即 Puppeteer,这个框架你可以看出是异步版的 Selenium。

对于爬虫程序,一个万能公式:

爬虫程序 = 网络请求 + 数据解析 + 数据存储

这三部分就对应这爬虫的基础,任何一个爬虫程序都会保存这三部分的内容,一些复杂的爬虫无非是在此基础上添加些别的内容。一个爬虫工程师反爬能力有多强,他的爬虫实力就有多高。

03 获取不到网页的全部代码?

问题:通过request方法获取的网页代码与在浏览器看到的网页源码不一致;

解决方法:由于很多网页的数据传输是通过js命令传到网页的,因此使用request()方法不能获取通过js传递过来的信息代码。此时通过使用selenium库来模拟浏览器运行,就像真正的用户在操作一样,可通过此方法可获得该网页的源码。

from selenium.webdriver.support.wait import WebDriverWaitbrowser = webdriver.Chrome()browser.get(Url)html = browser.page_source

04 点击下一页时网页网页不变 

问题:

在爬取的过程中,由于要爬取每个律师详细信息所对应的网址,因此涉及到翻页的问题,但在网页上实时点击下一页时发现网址并没有发生变化。

解决方法:

通过使用selenium中nextpagebutton.click()方法来模拟跳转到下一页,从而对下一页的内容进行获取。

nextpagebutton = browser.find_element_by_xpath('//*[@class="next_page"]') # 定位到“下一页”按钮 nextpagebutton.click() # 模拟点击下一页 wait = WebDriverWait(browser, 10) # 浏览器等待10s

05 文本节点问题 

首先看两个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 属性的话尽量用 id 来查找,因为整个页面 id 是唯一的。用 class 查找的话,最好现在浏览器的网页源码中 Ctrl + F 搜索一下,相同 class 的标签有多少。(如果比较多的话,可以尝试先查找他的父标签,缩小范围之后再查找)然后我们再讲讲 find_all 函数,适用于一次性查找一类型的很多标签的情况,

比如下图这种情况:

列表中的每一个 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 获取标签中的数据

查找到标签之后,又该如何获取标签中的数据呢?

标签中的数据位置,一般有两种情况:

这是数据这是数据

如果是第一种情况很简单,直接 pTip.text 即可;(pTip 是前面已经获取好的 p 标签)

如果是第二种情况,需要看它是在哪一个属性里的数据,比如我们要获取上面 a 标签中的 href 属性中的链接,可以 link = aTip["href"] 即可。(aTip 是前面已经获取好的 a 标签)。

08 去除指定内容

去除获取内容首尾的指定字符串;

问题:

有时我们在爬虫过程中,获取到的信息并不是全部都是我们想要获取的内容,如果想要去除指定内容。

例如:字符串 a = [“aaaa”],但是只想获取中间的aaaa

解决:

可以通过使用正则表达式来提取文本内容,去除符号,但如果使用此方法,字符串中间包含的符号也会被去掉。如果确定想要获取的文本中间不含有符号,可以选用正则表达式。

x = strTemp.xpath('./div[3]/div[1]/div/div/div[1]/div/ul/li[14]//text()') xx = str(x) email = re.search(r'[\u4e00-\u9fa5a-zA-Z0-9]+', xx)

第二种方法是使用strip()方法来去除首尾的符号;

a = td[1].get_text().strip('[""]')

09 转化为字符串类型

通过正则表达式获取的内容是match类型,如何转化为字符串str类型?

解决办法:使用group(0)来转化为字符串类型

email = email.group(0)

10 滥用遍历文档树

常见的方法有:

  • contents
  • descendants
  • parent
  • next_sibling
  • next_element

这些方法都会遍历文档树中的所有节点,包括文本节点。也就是说只要你使用这些方法,你就一定会选择出许多文本节点,因为文本节点无处不在,换行、空格等。

解决方法:使用过滤器find等方法;

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: # 获取会话指针 with connection.cursor() as cursor: # 创建SQL语句 sql = "insert into layer(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 循环内外出现的问题,修改后解决此问题,用一些小例子做测试:

#测试一 x=0 for i in range(0,10): for j in range(0,10): print x x+=1 for i in range(0,10): x=0 for j in range(0,10): print x x+=1 #测试二 >>> x=0 >>> for i in range(0,10): print('the i is',i) x=0 for j in range(0,10): print('the j 
                
                

-六神源码网