关于爬虫那档事

前言

本文主要以代码形式讲解爬虫,代码中有注释可助理解,代码都是可以运行的,或许有些网站变化,导致无法访问或者属性元素找不到,要想运行的话,自个在网站里找元素位置并在代码中更改。
代码都是在PyCharm编译下写的,读者也可以下个PyCharm,还是很好用的。

顺便说几个快捷键,都是对于选中的语句:
Tab			#换行
Shift+Tab			#取消换行
Ctrl+?键			#多行注释(取消注释)

爬虫分类
还是先说下分类吧(教科书式,)

•	通用爬虫:通用爬虫是搜索引擎(Baidu、Google、Yahoo等)“抓取系统”的重要组成部分。
主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
简单来讲就是尽可能的;把互联网上的所有的网页下载下来,放到本地服务器里形成备分,在对这些网页做相关处理(提取关键字、去掉广告),最后提供一个用户检索接口。
•	聚焦爬虫:聚焦爬虫是根据指定的需求抓取网络上指定的数据。
例如:获取豆瓣上电影的名称和影评,而不是获取整张页面中所有的数据值。
•	增量式爬虫:增量式是用来检测网站数据更新的情况,且可以将网站更新的数据进行爬取
•	深层网络爬虫:大部分不能通过静态的URL获取,隐藏在搜索表单之后,只有用户提交一些关键词之后才能获得的网络页面。

requests爬取

爬取步骤:
1、指定url
2、发送请求
3、获取响应
4、数据解析
5、永久化存储

下面算是最基本的爬虫了,其中没有数据解析,看下爬取过程就行了

# -*- coding: utf-8 -*-
#加上面这个是防止中文乱码
import requests
#爬取河南理工大学主页
# 1 指定URL
get_url = "http://www.hpu.edu.cn/www/index.html"
#UA伪装
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}
# 2 发送请求
response = requests.get(url = get_url, headers = header)
# 3 获取响应数据
response.encoding = 'utf-8'
page_text =  response.text
# 4 永久化存储
fp = open("hpu.html",'w',encoding = 'utf-8')
fp.write(page_text)
fp.close()

get参数
下面代码是get请求时带有params参数,算是获取动态数据,获取到的是json类型的响应数据

# -*- coding: utf-8 -*-
import requests
import json
#豆瓣电影
url="https://movie.douban.com/j/chart/top_list?"
headers ={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}
start = input("请输入起始位置:")
limit = input("请输入电影数量:")
params = {
        'type': '24',
        'interval_id': '100:90',
        'action':'' ,
        'start': start,
        'limit': limit
}
response = requests.get(url=url,params=params,headers=headers)
movie = response.json()
fp = open("douban.json",'w',encoding='utf-8')
json.dump(movie,fp=fp,ensure_ascii=False)
fp.close()
response.close()

post请求参数

# -*- coding: utf-8 -*-
import requests
import json
#百度翻译
url="https://fanyi.baidu.com/sug"
headers ={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}
word = input("请输入想要查询的单词:")
data = {
        "kw": word
}
response = requests.post(url=url,data=data,headers=headers)
dic = response.json()
print(dic["data"][0]['k'])
print(dic["data"][0]['v'])
filename = word+".json"
fp = open(filename,'w',encoding='utf-8')
json.dump(dic,fp=fp,ensure_ascii=False)
fp.close()

运行结果:
在这里插入图片描述
生成的json文件,类型是字典:
在这里插入图片描述

数据解析

re用到的语句

import re
re.compile(pattern, flags=0)		#将一个正则表达式模式编译为一个正则表达式对象
re.findall(pattern, string, flags=0)	#匹配到字符串中所有符合条件的元素
re.finditer(pattern, string ,flags=0)
.groups()		#匹配对象函数来获取匹配表达式。
.sprit()		#去掉字符串里空格和换行

bs4语句

from bs4 import BeautifulSoup			#调用库
page=BeautifulSoup(string,'lxml')		#先将字符串转换为bs4识别的类型
table = page.find("table",class_="hq_table")              #class属性:class_
table = page.find("table",attrs={"class":"hq_table"})		# #指定属性 
trs = table.find_all("tr")		#找到所有tr标签

#获取文本
.string
.text
.get_text()

.get('title')		#用.get(‘属性值’)的方法获取标签里面的属性值

xpath语句

from lxml import etree
tree = etree.HTML(html)		#解析
/div[@class='coll']		#指定属性
/text()		#获取文本
/@href		#获取属性
/

三个特点:
re正则表达式:具有灵活、逻辑性和功能性非常强的特点,能迅速地通过表达式从字符串中找到所需信息的优点,但对刚接触的人,比较晦涩难懂。
bs4:提供了一些简单的函数用来处理导航、搜索、修改分析树等功能,可为用户提供需要抓取的数据,非常简便,仅需少量的代码就可以写出一个完整的应用程序,不仅支持python标准库中的HTML解析器,还支持一些第三方的解析器。
xpath:选择功能十分强大,提供了非常简洁明了的路径选择表达式,提供了超过100个内建函数,用于字符串、数值、时间的匹配,以及节点、序列的处理等等,几乎所有定位的节点都可以用Xpath来选择。

re正则化

正则的语法:使用元字符进行排列组合用来匹配字符串
安装re库

.*			贪婪匹配,匹配所有符合的
.*? 		惰性匹配 ,只匹配第一次成功

在这里插入图片描述

正则化匹配

# -*- coding: utf-8 -*-
import re
content = """
<div class='焦作'><span id='1001'>河南理工</span></div>
<div class='郑州'><span id='2001'>郑州大学</span></div>
<div class='开封'><span id='3001'>河南大学</span></div>
<div class='洛阳'><span id='4001'>河南科大</span></div>
"""
obj = re.compile(r"<div class='(.*?)><span id='.*?"
           r"'>(?P<name>.*?)</span></div>",re.S)	#re.S必须要带,不然.*不匹配
result = re.findall(obj,content)
print(result)

运行结果:
在这里插入图片描述

爬取豆瓣Top250前十页

# -*- coding: utf-8 -*-
import requests
import re

url = 'https://movie.douban.com/top250'
hd = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Mobile Safari/537.36'
}

f = open("movie.txt",'w',encoding='utf-8')
for i in range(10):
    n = i*25
    params = {
        'start': n,
        'filter': ''
    }
    #url = url + '?start={}&filter='.format(n)
    response = requests.get(url, headers=hd, params=params)
    response.encoding = 'utf-8'
    page_text = response.text
    #print(page_text)
    obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">'
                     r'(?P<name>.*?)</span>.*?<p class="">.*?<br>(?P<year>.*?)'
                     r'&nbsp.*?<div class="star">.*?property="v:average">(?P<score>.*?)</span>'
                     r'.*?<span>(?P<num>.*?)人评价</span>',re.S)
    result = re.finditer(obj,page_text)
    for res in result:
        f.write(res.group("name"))
        f.write('\t')
        f.write(res.group("year").strip())
        f.write('\t')
        f.write(res.group("score"))
        f.write('\t')
        f.write(res.group('num'))
        f.write('\n')
    print('第{}页完成'.format(i+1))
f.close()

运行结果:
生成movie.txt文件:
在这里插入图片描述

bs4

bs4:通过标签的特征定位到想要获取的内容
安装BeautifulSoup库

(1)根据标签名查找
    - soup.a   只能找到第一个符合要求的标签
(2)获取属性
    - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
    - soup.a.attrs['href']   获取href属性
(3)获取其标签内的内容
    - soup.a.string
    - soup.a.text
    - soup.a.get_text()
   【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
    - soup.find('a')  找到第一个符合要求的
    - soup.find('a', title="xxx")
    - soup.find('a', alt="xxx")
    - soup.find('a', class_="xxx")		#属性值查找
    - soup.find('a', id="xxx")
(5)find_all:找到所有符合要求的标签
    - soup.find_all('a')
    - soup.find_all(['a','b']) 找到所有的a和b标签
    - soup.find_all('a', limit=2)  限制前两个
(6)根据选择器选择指定的内容
           select:soup.select('#feng')
    - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
	【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
#获取文本
.string
.text
.get_text()
.string可以返回当前节点中的内容,但是当前节点包含子节点时,.string不知道要获取哪一个节点中的内容,故返回空
.text(或.get_text())可以返回当前节点所包含的所有文本内容,包括当前节点的子孙节点

string与text:
在这里插入图片描述

bs4新发地代码实例

# -*- coding: utf-8 -*-
import requests
import csv
from bs4 import BeautifulSoup
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
}

url="http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
resp = requests.get(url=url,headers=headers)
#print(type(resp.text))
page=BeautifulSoup(resp.text,'lxml')
#print(type(page))
# table = page.find("table",class_="hq_table")              #class属性:class_
table = page.find("table",attrs={"class":"hq_table"})       #指定属性
#print(type(table),table)
trs = table.find_all("tr")      #匹配所有tr标签
vegs = trs[1:]
#print(vegs[0].string)
fp = open("price.csv","w",newline='',encoding="utf-8")     #有中文,utf-8编码格式,newline是防止多出现一行
csvwriter = csv.writer(fp)
for tr in vegs:
    tds = tr.find_all("td")
    #print(tds)
    name = tds[0].string    #菜名
    lowest = tds[1].string  #最低价
    aver = tds[2].string    #平均价
    highest = tds[3].string     #最高价
    scale = tds[4].string       #规格
    unit = tds[5].string        #单位
    date = tds[6].string        #发布日期
    #print(name+","+lowest+','+aver)
    csvwriter.writerow([name,lowest,aver,highest,scale,unit,date])      #csv保存方式
fp.close()
print('ok')
#爬取十页
# for i in range(10):
#     url = f'http://www.xinfadi.com.cn/marketanalysis/0/list/{i + 1}.shtml'
#     r = requests.get(url,headers=hd).content.decode('utf-8')
#     page = BeautifulSoup(r,'lxml')
#     tbody = page.find('div',class_='hangqing').find('table',class_='hq_table').findAll('tr')[1:]
#     for tr in tbody:
#         print(tr.text)

运行结果:
生成price.csv文件:
在这里插入图片描述

xpath

xpath用路径找到数据
安装lxml库

代码实例

# -*- coding: utf-8 -*-
from lxml import etree
html = """
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title> 河南理工大学 </title>
    </head>
    <body>
        <div>
            <p>计算机学院</p>
        </div>
        <div class = "dept">
            <p id="bigdata">大数据</p>
            <p>物联网</p>
            <a href="http://www.hpu.edu.cn/" title = "计算机",target = "_self">
                /<span>this is a span</span>
                计算机学院成立于1999年</a>
            <img src = "dfiles/11066/bwcx/dfiles/5455/images/top.png" alt="" />
        </div>

        <div class = "coll">
            <ul>
                <li><a href="http://www.sohu.com/" title = "souhu",target = "_self">搜狐</a></li>
                <li><a href="http://www.zzu.edu.cn/" title = "zhengda",target = "_self">郑大</a></li>
                <li><a href="http://www.hu.edu.cn/" class = "heda",target = "_self">河大</a></li>
                <li><a href="http://www.baidu.edu.cn/" title = "baidu",target = "_self">百度</a></li>
                <li><b>数据科学与大数据技术</b></li>
                <li><i>计算机科学与技术</i></li>
            </ul>
        </div>

    </body>
</html>
"""
tree = etree.HTML(html)
# print(tree)
# result1 = tree.xpath("/html")
# print(result1)

# result2 = tree.xpath("/html/head/title/text()")
# print(result2)
#[' 河南理工大学 ']

# result3 = tree.xpath("/html//li[1]/a/text()")
# print(result3)
#['搜狐']

result4 = tree.xpath("/html/body/div[@class='coll']/ul")		#指定属性
# print(result4)
#[<Element ul at 0x2982ee2ff00>]
result5 = result4[0].xpath("./li")		#./当前目录
# print(result5)
for i in result5:
    # print(i)
    # print(i.xpath("./*/text()"))
    print(i.xpath("./a/@href"))		#获取href属性

运行结果:
在这里插入图片描述

selenium

selenium是一个用电脑模拟人操作浏览器网页,可以实现自动化,测试等!还有就是只要是肉眼能在网页看到的selenium都能爬取,对动态数据爬取很是方便。

准备工作:

  1. 安装seleniumm
    pip install selenium

  2. 下载浏览器驱动
    Firefox浏览器驱动:geckodriver
    Chrome浏览器驱动:chromedriver
    Edge浏览器驱动:MicrosoftWebDriver
    打开本地浏览器,查看浏览器版本,然后下载对应的驱动器版本
    下载后,(解压),把驱动器放到与python.exe同一目录下。用PyCharm的运行一个代码后有显示python.exe路径。

selenium模拟浏览器爬取拉勾网职位信息

# -*- coding: utf-8 -*-
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from lxml import etree
import time

#隐藏浏览器,就浏览器不弹出来
# opt = Options()
# opt.add_argument('--headless')
# opt.add_argument('--disable-gpu')
# web = Chrome(options=opt)

web = Chrome()
url = 'https://www.lagou.com/'
web.get(url)
web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a').click()    #选择城市
time.sleep(1)
web.find_element_by_xpath('//*[@id="search_input"]').send_keys('python',Keys.ENTER)    #搜索JAVA,回车
for i in range(3):
    #爬取3页
    li_list = web.find_elements_by_xpath('//*[@id="s_position_list"]/ul/li')    #每页所有职业,列表
    for li in li_list:
        time.sleep(1)
        #//点进职业详细信息(就点击),这种方法以防页面有滚动,无法点击现象。

        element = li.find_element_by_xpath('./div[1]/div[1]/div[1]/a/h3')
        web.execute_script("arguments[0].click();", element)        #这种方法防止找不到元素
        #li.find_element_by_xpath('./div[1]/div[1]/div[1]/a/h3').click()
        
        #//切换新打开的窗口,即职业详细信息窗口
        handlers = web.window_handles
        web.switch_to.window(handlers[-1])

        time.sleep(1)   #停一秒是防止页面没有加载出来,元素找不到而出错
        job = web.find_element_by_class_name('position-head-wrap-position-name').text   #职业名
        company = web.find_element_by_class_name('company').text            #公司名
        salary = web.find_element_by_class_name('salary').text              #薪水
        adress = web.find_element_by_class_name('publish_time').find_element_by_class_name('company').text      #公司地址
        #下面try是找岗位职责,因为有些页面信息是折叠的,所以先判断下是否有可点击折叠元素
        try:
            web.find_element_by_xpath('//*[@id="container"]/div[1]/div[1]/div[1]/span').click()
            duty = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]/div').text
        except:
            duty = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]/div').text
        print(job,company,salary,adress[:-4],duty,'\n')
        web.close()    #关闭当前页面
        time.sleep(1)
        web.switch_to.window(handlers[0])       #转到最初那个窗口
    web.find_element_by_class_name('pager_next ').click()    #点击下一页
#web.close()	#关闭浏览器
#web.quit()		#关闭浏览器所有打开的窗口

运行结果:
在这里插入图片描述
若是出错,下面出错信息,不是代码问题,因为你他这个网址会记录你访问次数啥的,很烦人,体验下这个过程就行了。
在这里插入图片描述

验证码

有些登录操作需要验证码,本节讲selenium获取验证码过程
首先你需要个识别验证码的第三方工具,这里推荐个超级鹰,关注公众能白嫖使用许多次,够支持你学会了。

selenium验证码12306登录操作代码

# -*- coding: utf-8 -*-
import requests
from selenium.webdriver import Chrome
import time
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains
from hashlib import md5

url = 'https://kyfw.12306.cn/otn/resources/login.html'
web = Chrome()
web.get(url)
web.maximize_window()       #窗口最大化
# web.refresh()     #刷新
web.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
# time.sleep(1)
web.find_element_by_xpath('//*[@id="J-userName"]').send_keys('帐号')      #这里需要输入你12306的帐号
web.find_element_by_xpath('//*[@id="J-password"]').send_keys('密码')      #12306密码

web.save_screenshot('page_.png')        #截全屏
img = web.find_element_by_xpath('//*[@id="J-loginImg"]')        #找到验证码位置(通过属性定位)
loc = img.location
size = img.size                 #验证码大小
rect = (loc['x'],loc['y'],loc['x']+size['width'],loc['y']+size['height'])           #验证码左上角和右下角坐标
i = Image.open('./page_.png')
code = './code_.png'
frame = i.crop(rect)            #吧把验证码部分截下来
frame.save(code)

#下面类代码是超级鹰验证码识别框架,不用管
class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password =  password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


chaojiying = Chaojiying_Client('用户帐号', '密码', '918789')	#帐号,密码用自己的 #用户中心>>软件ID 生成一个替换 96001
im = open('code_.png', 'rb').read()			            #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
clicks = chaojiying.PostPic(im, 9005)['pic_str']        #pic_str是字典里的一个键,值是验证码(点击坐标)
print(clicks)
loc_all = clicks.split('|')
#模拟图片验证码点击操作
for xy in loc_all:
    x,y = xy.split(',')
    ActionChains(web).move_to_element_with_offset(img,int(x),int(y)).click().perform()

web.find_element_by_xpath('//*[@id="J-login"]').click()     #点击登录

#拖动滑块
time.sleep(1)
#web.switch_to.alert.accept()        #切换到弹出框
huakuai = web.find_element_by_xpath('//*[@id="nc_1_n1z"]')
#time.sleep(1)
# move_to_gap(huakuai,get_track(300))

# 防止12306禁止selenium
#使用selenium滑动会被12306检测到,需要伪装一下
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
web.execute_script(script)

#滑块移动
span = web.find_element_by_xpath('//*[@id="nc_1_n1z"]')
action = ActionChains(web)
action.click_and_hold(span)
action.move_by_offset(350, 0).perform()
action.release()

print('登陆了成功!')

代码运行说明:
1、下面这个调一下,在设置里面。不调的话验证码截剪的不对
在这里插入图片描述

2、代码里需要填写两处帐号、密码,一个是12306、另一个是超级鹰的
3、出错可能验证码没有成功,这个代码只会测试一次,没成功就重新运行代码。

运行:
截的网页:
在这里插入图片描述
截剪的验证码:
在这里插入图片描述
输出:
在这里插入图片描述

好了,到此本片文章结束,希望你能有所收获,捏!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值