突破%

 

python爬虫之基础

爬虫基础知识

python基础


1、Python 编写爬虫程序的流程:

先由 urllib 模块的 request 方法打开 URL 得到网页 HTML 对象。  -- 请求网页
使用浏览器打开网页源代码分析网页结构以及元素节点。              -- 获取数据
通过 Beautiful Soup 或则正则表达式提取数据。                  -- 解析数据 
存储数据到本地磁盘或数据库。                                  -- 保存数据
难点:登录与会话保持

面向对象的代码结构:
# 程序结构
class xxxSpider(object):
    def __init__(self):
        # 定义常用变量,比如url或计数变量等
    def get_html(self):
        # 获取响应内容函数,使用随机User-Agent
    def parse_html(self):
        # 使用正则表达式来解析页面,提取数据
    def write_html(self):
        # 将提取的数据按要求保存,csv、MySQL数据库等 
    def run(self):
        # 主函数,用来控制整体逻辑
       
if __name__ == '__main__':
    # 程序开始运行时间
    spider = xxxSpider()
    spider.run()


2、熟悉网络构成
HTML、css、js

3、静态网页、动态网页
静态网页的数据全部包含在 HTML 中。
动态网页指的是采用了动态网页技术的页面, 网页可以局部更新,可以异步加载。

4、抓包工具  Fiddler

################爬虫库############################
5、爬虫库 urllib
1) urlopen()
    表示向网站发起请求并获取响应对象,如下所示:
    urllib.request.urlopen(url,timeout)
    urlopen() 有两个参数,说明如下:
    url:表示要爬取数据的 url 地址。
    timeout:设置等待超时时间,指定时间内未得到响应则抛出超时异常。
2) Request()
    该方法用于创建请求对象、包装请求头,比如重构 User-Agent(即用户代理,指用户使用的浏览器)使程序更像人类的请求,而非机器。重构 User-Agent 是爬虫和反爬虫斗争的第一步。在下一节会做详细介绍。
    urllib.request.Request(url,headers)
    参数说明如下:
    url:请求的URL地址。
    headers:重构请求头。
3) html响应对象方法
    bytes = response.read() # read()返回结果为 bytes 数据类型
    string = response.read().decode() # decode()将字节串转换为 string 类型
    url = response.geturl() # 返回响应对象的URL地址
    code = response.getcode() # 返回请求时的HTTP响应码
4) 编码解码操作
    #字符串转换为字节码
    string.encode("utf-8") 
    #字节码转换为字符串
    bytes.decode("utf-8") 

6、User-Agent
随机获取UA:pip install fake-useragent
from fake_useragent import UserAgent
#实例化一个对象
ua=UserAgent()
#随机获取一个ie浏览器ua
print(ua.ie)
print(ua.ie)
#随机获取一个火狐浏览器ua
print(ua.firefox)
print(ua.firefox)

7、爬取网页
from urllib import request
from urllib import parse

# 拼接URL地址
def get_url(word):
  url = 'http://www.baidu.com/s?{}'
  #此处使用urlencode()进行编码
  params = parse.urlencode({'wd':word})
  url = url.format(params)
  return url

# 发请求,保存本地文件
def request_url(url,filename):
  headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
  # 请求对象 + 响应对象 + 提取内容
  req = request.Request(url=url,headers=headers)
  res = request.urlopen(req)
  html = res.read().decode('utf-8')
  # 保存文件至本地
  with open(filename,'w',encoding='utf-8') as f:
    f.write(html)

# 主程序入口
if __name__ == '__main__':
  word = input('请输入搜索内容:')
  url = get_url(word)
  filename = word + '.html'
  request_url(url,filename)

8、爬取贴吧
from urllib import request,parse
import time
import random
from ua_info import ua_list #使用自定义的ua池

#定义一个爬虫类
class TiebaSpider(object):
    #初始化url属性
    def __init__(self):
        self.url='http://tieba.baidu.com/f?{}'

    # 1.请求函数,得到页面,传统三步
    def get_html(self,url):
        req=request.Request(url=url,headers={'User-Agent':random.choice(ua_list)})
        res=request.urlopen(req)
        #windows会存在乱码问题,需要使用 gbk解码,并使用ignore忽略不能处理的字节
        #linux不会存在上述问题,可以直接使用decode('utf-8')解码
        html=res.read().decode("gbk","ignore")
        return html
    # 2.解析函数,此处代码暂时省略,还没介绍解析模块
    def parse_html(self):
        pass
    # 3.保存文件函数
    def save_html(self,filename,html):
        with open(filename,'w') as f:
            f.write(html)
    # 4.入口函数
    def run(self):
        name=input('输入贴吧名:')
        begin=int(input('输入起始页:'))
        stop=int(input('输入终止页:'))
        # +1 操作保证能够取到整数
        for page in range(begin,stop+1):
            pn=(page-1)*50
            params={
                'kw':name,
                'pn':str(pn)
            }
            #拼接URL地址   
            params=parse.urlencode(params)
            url=self.url.format(params)
            #发请求
            html=self.get_html(url)
            #定义路径
            filename='{}-{}页.html'.format(name,page)
            self.save_html(filename,html)
            #提示
            print('第%d页抓取成功'%page)
            #每爬取一个页面随机休眠1-2秒钟的时间
            time.sleep(random.randint(1,2))
#以脚本的形式启动爬虫
if __name__=='__main__': 
    start=time.time()
    spider=TiebaSpider() #实例化一个对象spider
    spider.run() #调用入口函数
    end=time.time()
    #查看程序执行时间
    print('执行时间:%.2f'%(end-start))  #爬虫执行时间

9、正则表达式
python的re模块
1) re.compile()
该方法用来生成正则表达式对象,其语法格式如下:
regex=re.compile(pattern,flags=0)
参数说明:
pattern:正则表达式对象。
flags:代表功能标志位,扩展正则表达式的匹配。
2) re.findall()
根据正则表达式匹配目标字符串内容。
re.findall(pattern,string,flags=0)
该函数的返回值是匹配到的内容列表,如果正则表达式有子组,则只能获取到子组对应的内容。参数说明如下:
pattern:正则表达式对象。
string:目标字符串
flags:代表功能标志位,扩展正则表达式的匹配。
3) regex.findall()
该函数根据正则表达式对象匹配目标字符串内容。其语法格式如下:
regex.findall(string,pos,endpos)
参数说明:
string 目标字符串。
pos 截取目标字符串的开始匹配位置。
endpos 截取目标字符串的结束匹配位置。
4) re.split()
该函数使用正则表达式匹配内容,切割目标字符串。返回值是切割后的内容列表。参数说明:
re.split(pattern,string,flags = 0)
参数说明:
pattern:正则表达式。
string:目标字符串。
flags:功能标志位,扩展正则表达式的匹配。
5) re.sub
该函数使用一个字符串替换正则表达式匹配到的内容。返回值是替换后的字符串。其语法格式如下:
re.sub(pattern,replace,string,max,flags = 0)
其参数说明:
pattern:正则表达式。
replace:替换的字符串。
string:目标字符串。
max:最多替换几处,默认替换全部,
flags:功能标志位,扩展正则表达式的匹配。
5) re.search()
匹配目标字符串第一个符合的内容,返回值为匹配的对象。语法格式如下:
re.search(pattern,string,flags=0)
参数说明:
pattern:正则表达式
string:目标字符串

10、CSV读写
CSV文件写入
1) csv.writer()
csv 模块中的 writer 类可用于读写序列化的数据,其语法格式如下:
writer(csvfile, dialect='excel', **fmtparams)
参数说明:
csvfile:必须是支持迭代(Iterator)的对象,可以是文件(file)对象或者列表(list)对象。
dialect:编码风格,默认为 excel 的风格,也就是使用逗号,分隔。
fmtparam:格式化参数,用来覆盖之前 dialect 对象指定的编码风格。

示例如下:
import csv
# 操作文件对象时,需要添加newline参数逐行写入,否则会出现空行现象
with open('eggs.csv', 'w', newline='') as csvfile:
    # delimiter 指定分隔符,默认为逗号,这里指定为空格
    # quotechar 表示引用符
    # writerow 单行写入,列表格式传入数据
    spamwriter = csv.writer(csvfile, delimiter=' ',quotechar='|')
    spamwriter.writerow(['www.biancheng.net'] * 5 + ['how are you'])
    spamwriter.writerow(['hello world', 'web site', 'www.biancheng.net'])
eggs.csv 文件内容如下:
www.biancheng.net www.biancheng.net www.biancheng.net www.biancheng.net www.biancheng.net |how are you|
|hello world| |web site| www.biancheng.net
其中,quotechar 是引用符,当一段话中出现分隔符的时候,用引用符将这句话括起来,以能排除歧义。

如果想同时写入多行数据,需要使用 writerrows() 方法,代码如下所示:
import csv
with open('aggs.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    # 注意传入数据的格式为列表元组格式
    writer.writerows([('hello','world'), ('I','love','you')])

2) csv.DictWriter()
当然也可使用 DictWriter 类以字典的形式读写数据,使用示例如下:
import csv
with open('names.csv', 'w', newline='') as csvfile:
    #构建字段名称,也就是key
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    # 写入字段名,当做表头
    writer.writeheader()
    # 多行写入
    writer.writerows([{'first_name': 'Baked', 'last_name': 'Beans'},{'first_name': 'Lovely', 'last_name': 'Spam'}])
    # 单行写入
    writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})

CSV文件读取
1) csv,reader()
csv 模块中的 reader 类和  DictReader 类用于读取文件中的数据,其中 reader() 语法格式如下:
csv.reader(csvfile, dialect='excel', **fmtparams)
应用示例如下:
import csv
with open('eggs.csv', 'r', newline='') as csvfile:
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    for row in spamreader:
        print(', '.join(row))

2) csv.DictReader()
应用示例如下:
import csv
with open('names.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row['first_name'], row['last_name'])

11、 爬取猫眼
from urllib import request
import re
import time
import random
import csv
from ua_info import ua_list

# 定义一个爬虫类
class MaoyanSpider(object): 
    # 初始化
    # 定义初始页面url
    def __init__(self):
        self.url = 'https://maoyan.com/board/4?offset={}'
    
    # 请求函数
    def get_html(self,url):
        headers = {'User-Agent':random.choice(ua_list)}
        req = request.Request(url=url,headers=headers)
        res = request.urlopen(req)
        html = res.read().decode()
        # 直接调用解析函数
        self.parse_html(html)
    
    # 解析函数
    def parse_html(self,html):
        # 正则表达式
        re_bds = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>'
        # 生成正则表达式对象
        pattern = re.compile(re_bds,re.S)
        # r_list: [('我不是药神','徐峥,周一围,王传君','2018-07-05'),...] 列表元组
        r_list = pattern.findall(html)
        self.save_html(r_list)

    # 保存数据函数,使用python内置csv模块
    def save_html(self,r_list):
        #生成文件对象  
        with open('maoyan.csv','a',newline='',encoding="utf-8") as f:
            #生成csv操作对象
            writer = csv.writer(f)
            #整理数据
            for r in r_list:
                name = r[0].strip()
                star = r[1].strip()[3:]
                # 上映时间:2018-07-05
                # 切片截取时间
                time = r[2].strip()[5:15]
                L = [name,star,time]
                # 写入csv文件
                writer.writerow(L)
                print(name,time,star)

    # 主函数
    def run(self):
        #抓取第一页数据
        for offset in range(0,11,10):
            url = self.url.format(offset)
            self.get_html(url)
            #生成1-2之间的浮点数
            time.sleep(random.uniform(1,2))

# 以脚本方式启动
if __name__ == '__main__':
    #捕捉异常错误
    try:
        spider = MaoyanSpider()
        spider.run()
    except Exception as e:
        print("错误:",e)

12、爬取猫眼,存储到数据库
# coding=gbk
from urllib import request
import re
import time
import random
from ua_info import ua_list
import pymysql

class MaoyanSpider(object):
    def __init__(self):
        #初始化属性对象
        self.url = 'https://maoyan.com/board/4?offset={}'
        #数据库连接对象
        self.db = pymysql.connect(
            'localhost','root','123456','maoyandb',charset='utf8')
        #创建游标对象
        self.cursor = self.db.cursor()

    def get_html(self,url):
        headers = {'User-Agent':random.choice(ua_list)}
        req = request.Request(url=url,headers=headers)
        res = request.urlopen(req)
        html = res.read().decode()
        # 直接解析
        self.parse_html(html)

    def parse_html(self,html):
        re_bds = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>'
        pattern = re.compile(re_bds,re.S)
        r_list = pattern.findall(html)
        self.save_html(r_list)

    def save_html(self, r_list):
        L = []
        sql = 'insert into movieinfo values(%s,%s,%s)'
        # 整理数据
        for r in r_list:
            t = (
                r[0].strip(),
                r[1].strip()[3:],
                r[2].strip()[5:15]
            )
            L.append(t)
            print(L)
        # 一次性插入多条数据 L:[(),(),()]
        try:
            self.cursor.executemany(sql,L)
            # 将数据提交数据库
            self.db.commit()
        except:
            # 发生错误则回滚
            self.db.rollback()

    def run(self):
        for offset in range(0,11,10):
            url = self.url.format(offset)
            self.get_html(url)
            time.sleep(random.uniform(1,3))

        # 断开游标与数据库连接
        self.cursor.close()
        self.db.close()

if __name__ == '__main__':
    start=time.time()
    spider = MaoyanSpider()
    spider.run()
    end=time.time()
    print("执行时间:%.2f" % (end-start))

13、电影天堂
# -*- coding: utf-8 -*-
from urllib import request
import re
import time
import random
import pymysql
from hashlib import md5
from ua_info import ua_list
import sys

class MovieSkySpider(object):
    def __init__(self):
        self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
        self.db = pymysql.connect(
            'localhost','root','123456','movieskydb',
            charset='utf8'
        )
        self.cursor = self.db.cursor()

    # 1.请求函数
    def get_html(self, url):
        headers = {'User-Agent': random.choice(ua_list)}
        req = request.Request(url=url, headers=headers)
        res = request.urlopen(req)
        # 本网站使用gb2312的编码格式
        html = res.read().decode('gb2312', 'ignore')

        return html

    # 2.正则解析函数
    def re_func(self,re_bds,html):
        pattern = re.compile(re_bds,re.S)
        r_list = pattern.findall(html)

        return r_list

    # 3.提取数据函数
    def parse_html(self,one_url):
        # 调用请求函数,获取一级页面
        one_html = self.get_html(one_url)
        re_bds = '<table width="100%".*?<td width="5%".*?<a href="(.*?)".*?ulink">.*?</table>'
        # 获取二级页面链接
        # link_list: ['/html//html/gndy/dyzz/20210226/61131.html','/html/xxx','','']
        link_list = self.re_func(re_bds,one_html)
        for link in link_list:
            # 判断是否需要爬取此链接
            # 1.获取指纹
            # 拼接二级页面url
            two_url = 'https://www.dytt8.net' + link
            s = md5()
            #加密url,需要是字节串
            s.update(two_url.encode())
            # 生成指纹,获取十六进制加密字符串,
            finger = s.hexdigest()
            # 2.通过函数判断指纹在数据库中是否存在
            if self.is_hold_on(finger):
                # 抓取二级页面数据
                self.save_html(two_url)
                time.sleep(random.randint(1,2))
                # 抓取后,把想用的url专属指纹存入数据库
                ins = 'insert into request_finger values (%s)'
                self.cursor.execute(ins,[finger])
                self.db.commit()
            else:
                sys.exit('更新完成')

    # 4.判断链接是否已经抓取过
    def is_hold_on(self,finger):
        # 查询数据库
        sql='select finger from request_finger where finger=%s'
        # execute()函数返回值为受影响的行数(即0或者非0)
        r = self.cursor.execute(sql,[finger])
        # 如果为0表示没有抓取过
        if not r:
            return True

    # 5.解析二级页面,获取数据(名称与下载链接)
    def save_html(self,two_url):
        two_html = self.get_html(two_url)
        re_bds = '<div class="title_all"><h1><font color=#07519a>(.*?)</font></h1> \
        </div>.*?<a.*?href="(.*?)".*?>.*?style="BACKGROUND-COLOR:.*?</a>'
        # film_list: [('name','downloadlink'),(),(),()]
        film_list = self.re_func(re_bds,two_html)
        print(film_list)
        # 插入数据库
        sql = 'insert into movieinfo values(%s,%s)'
        #L = list(film_list[0])
        self.cursor.executemany(sql,film_list)
        self.db.commit()
    
    #主函数 
    def run(self):
        # 二级页面后四页的正则表达式略有不同,需要重新分析
        for i in range(1,4):
            url = self.url.format(i)
            self.parse_html(url)

if __name__ == '__main__':
    spider = MovieSkySpider()
    spider.run()

14、requests
python -m pip install requests
1) requests.get()
该方法用于 GET 请求,表示向网站发起请求,获取页面响应对象。语法如下:
res = requests.get(url,headers=headers,params,timeout)
参数说明如下:
url:要抓取的 url 地址。
headers:用于包装请求头信息。
params:请求时携带的查询字符串参数。
timeout:超时时间,超过时间会抛出异常。
具体使用示例如下:
import requests
url = 'http://baidu.com'
response = requests.get(url)
print(response)
2) requests.post()
该方法用于 POST 请求,先由用户向目标 url 提交数据,然后服务器返回一个 HttpResponse 响应对象,语法如下:
response=requests.post(url,data={请求体的字典})
示例如下所示:
import requests
#百度翻译
url = 'https://fanyi.baidu.com'
#post请求体携带的参数,可通过开发者调试工具查看
#查看步骤:NetWork选项->Headers选项->Form Data
data = {'from': 'zh',
        'to': 'en',
        'query': '编程帮www.biancheng.net你好'
        }
response = requests.post(url, data=data)
print(response)

15、爬取图片
# -*- coding:utf8 -*-
import requests
import re
from urllib import parse
import os

class BaiduImageSpider(object):
    def __init__(self):
        self.url = 'https://image.baidu.com/search/flip?tn=baiduimage&word={}'
        self.headers = {'User-Agent':'Mozilla/4.0'}

    # 获取图片
    def get_image(self,url,word):
        #使用 requests模块得到响应对象
        res= requests.get(url,headers=self.headers)
        # 更改编码格式
        res.encoding="utf-8"
        # 得到html网页
        html=res.text
        print(html)
        #正则解析
        pattern = re.compile('"hoverURL":"(.*?)"',re.S)
        img_link_list = pattern.findall(html)
        #存储图片的url链接 
        print(img_link_list)

        # 创建目录,用于保存图片
        directory = 'C:/Users/Administrator/Desktop/image/{}/'.format(word)
        # 如果目录不存在则创建,此方法常用
        if not os.path.exists(directory):
            os.makedirs(directory)
        
        #添加计数 
        i = 1
        for img_link in img_link_list:
            filename = '{}{}_{}.jpg'.format(directory, word, i)
            self.save_image(img_link,filename)
            i += 1
    #下载图片
    def save_image(self,img_link,filename):
        html = requests.get(url=img_link,headers=self.headers).content
        with open(filename,'wb') as f:
            f.write(html)
        print(filename,'下载成功')

    # 入口函数 
    def run(self):
        word = input("您想要谁的照片?")
        word_parse = parse.quote(word)
        url = self.url.format(word_parse)
        self.get_image(url,word)

if __name__ == '__main__':
    spider = BaiduImageSpider()
    spider.run()

16、xpath

17、Xpath Helper

18、lxml
pip3 install lxml

19、lxml实例
# coding:utf8
import requests
from lxml import etree
from ua_info import ua_list
import random

class MaoyanSpider(object):
    def __init__(self):
        self.url='https://maoyan.com/board/4?offset=50'
        self.headers={'User-Agent':random.choice(ua_list)}


    def save_html(self):
        html=requests.get(url=self.url,headers=self.headers).text
        #jiexi
        parse_html=etree.HTML(html)

        # 基准 xpath 表达式,匹配10个<dd>节点对象
        dd_list=parse_html.xpath('//dl[@class="board-wrapper"]/dd') #列表放10个dd
        print(dd_list)
        # .// 表示dd节点的所有子节点后代节点
        # 构建item空字典将提取的数据放入其中
        item={}
        for dd in dd_list:
            # 处理字典数据,注意xpath表达式匹配结果是一个列表,因此需要索引[0]提取数据
            item['name']=dd.xpath('.//p[@class="name"]/a/text()')[0].strip()
            item['star']=dd.xpath('.//p[@class="star"]/text()')[0].strip()
            item['time']=dd.xpath('.//p[@class="releasetime"]/text()')[0].strip()
            #输出数据
            print(item)

    def run(self):
        self.save_html()

if __name__ == '__main__':
    spider=MaoyanSpider()
    spider.run()

20、爬取链家网
#coding:utf8
import requests
import random
from lxml import etree
import time
#提供ua信息的的包
from fake_useragent import UserAgent

class LinajiaSpider(object):
    def __init__(self):
        self.url='https://bj.lianjia.com/ershoufang/pg{}/'
        #计数,请求一个页面的次数,初始值为1
        self.blog=1

    # 随机取一个UA
    def get_header(self):
        #实例化ua对象
        ua=UserAgent()
        headers={'User-Agent':ua.random}
        return headers
    #发送请求
    def get_html(self,url):  
       #在超时间内,对于失败页面尝试请求三次
        if self.blog<=3:
            try:
                res=requests.get(url=url,headers=self.get_header(),timeout=3)
                html=res.text
                return html
            except Exception as e:
                print(e)
                self.blog+=1
                self.get_html(url)

    # 解析提取数据
    def parse_html(self,url):
        html=self.get_html(url)
        if html:
            p=etree.HTML(html)
            #基准xpath表达式-30个房源节点对象列表
            h_list=p.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
            #所有列表节点对象
            for h in h_list:
                item={}
                #名称
                name_list=h.xpath('.//a[@data-el="region"]/text()')
                #判断列表是否为空
                item['name']=name_list[0] if name_list else None
    #户型+面积+方位+是否精装..['2室1厅 | 88.62平米 | 北 南 | 简装 | 顶层(共6层) | 2004年建 | 板楼']
                info_list=h.xpath('.//div[@class="houseInfo"]/text()')
                #判断列表是否为空
                if info_list:
                    L=info_list[0].split('|')
          # ['2室1厅 ', ' 88.62平米 ', ' 北 南 ', ' 简装 ', ' 顶层(共6层) ', ' 2004年建 ', ' 板楼']
                    if len(L) >= 5:
                        item['model']=L[0].strip()
                        item['area']=L[1].strip()
                        item['direction']=L[2].strip()
                        item['perfect']=L[3].strip()
                        item['floor']=L[4].strip()
                #区域+总价+单价

                address_list=h.xpath('.//div[@class="positionInfo"]/a/text()')
                item['address']=address_list[0].strip() if address_list else None

                total_list=h.xpath('.//div[@class="totalPrice"]/span/text()')
                item['total_list']=total_list[0].strip() if total_list else  None

                price_list=h.xpath('.//div[@class="unitPrice"]/span/text()')
                item['price_list']=price_list[0].strip() if price_list else None
                print(item)

     # 入口函数
    def run(self):
        try:
            for i in range(1,101):
                url=self.url.format(i)
                self.parse_html(url)
                time.sleep(random.randint(1,3))
                #每次抓取一页要初始化一次self.blog
                self.blog=1
        except Exception as e:
            print('发生错误',e)

if __name__ == '__main__':
    spider=LinajiaSpider()
    spider.run()

21、有道翻译
#coding:utf8
import random
import time
from hashlib import md5
import requests


class YoudaoSpider(object):
    def __init__(self):
        # url一定要写抓包时抓到的POST请求的提交地址,但是还需要去掉 url中的“_o”,
        # “_o”这是一种url反爬策略,做了页面跳转,若直接访问会返回{"errorCode":50}
        self.url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
        self.headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
        }
    # 获取lts时间戳,salt加密盐,sign加密签名
    def get_lts_salt_sign(self,word):
        lts=str(int(time.time()*1000))
        salt=lts+str(random.randint(0,9))
        string = "fanyideskweb" + word + salt + "Tbh5E8=q6U3EXe+&L[4c@"
        s=md5()
        s.update(string.encode())
        sign=s.hexdigest()
        print(lts,salt,sign)
        return lts,salt,sign

    def attack_yd(self,word):
        lts,salt,sign=self.get_lts_salt_sign(word)

        #构建form表单数据
        data={
            "i": word,
            "from": "AUTO",
            "to": "AUTO",
            "smartresult": "dict",
            "client": "fanyideskweb",
            "salt": salt,
            "sign": sign,
            "lts": lts,
            "bv": "cda1e53e0c0eb8dd4002cefc117fa588",
            "doctype": "json",
            "version": "2.1",
            "keyfrom": "fanyi.web",
            "action": "FY_BY_REALTlME"
        }
        #使用 reqeusts.post()方法提交请求
        res = requests.post(
            url=self.url,
            data=data,
            headers=self.headers,

        )
        # res.json() 将json格式的字符串转为python数据类型
        # 客户端与服务器数据交互以json字符串传递,因此需要将它转换为python数据类型
        html=res.json()
        print(html)
        # 查看响应结果response  html:{"translateResult":[[{"tgt":"hello","src":"你好"}]],"errorCode":0,"type":"zh-CHS2en"}
        result=html["translateResult"][0][0]["tgt"]
        print('翻译结果:', result)

    def run(self):
        try:
            word=input('请输入要翻译的单词:')
            self.attack_yd(word)
        except Exception as e:
            print(e)

if __name__ == '__main__':
    spider=YoudaoSpider()
    spider.run()

22、爬取豆瓣
#coding:utf8
import requests
import time
import random
import re
import json
from ua_info import ua_list


class DoubanSpider(object):
    def __init__(self):
        self.url = 'https://movie.douban.com/j/chart/top_list?'
        self.i = 0

    # 获取随机headers
    def get_headers(self):
        headers = {'User-Agent':random.choice(ua_list)}
        return headers

    # 获取页面
    def get_page(self,params):
      # 将json转换为 python 数据类型,并返回
      html = requests.get(url=self.url,params=params,headers=self.get_headers()).text
      html=json.loads(html)
      self.parse_page(html)

    # 解析并保存数据
    def parse_page(self,html):
       item = {}
        # html列表类型: [{电影1},{电影2},{电影3}...]
       for one in html:
            # 名称 + 评分
           item['name'] = one['title'].strip()
           item['score'] = float(one['score'].strip())
           print(item)
           self.i += 1

    # 获取电影总数
    def total_number(self,type_number):
        # F12抓包抓到的地址,type表示电影类型
        url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(type_number)
        headers = self.get_headers()
        html = requests.get(url=url,headers=headers).json()
        total = int(html['total'])
        return total

    # 获取所有电影的类型和对应type值
    def get_all_type_films(self):
        # 获取类型与类型码
        url = 'https://movie.douban.com/chart'
        headers = self.get_headers()
        html = requests.get(url=url,headers=headers).text
        re_bds = r'<a href=.*?type_name=(.*?)&type=(.*?)&.*?</a>'
        pattern = re.compile(re_bds,re.S)
        r_list = pattern.findall(html)
        # 存放所有类型和对应类型码大字典
        type_dict = {}
        #定义一个选择电影类型的菜单
        menu = ''
        for r in r_list:
            type_dict[r[0].strip()] = r[1].strip()
            # 获取input的菜单,显示所有电影类型
            menu += r[0].strip() + '|'

        return type_dict,menu

    # 主程序入口函数
    def main(self):
        # 获取type的值
        type_dict,menu = self.get_all_type_films()
        menu = menu + '\n你想了解什么类型电影:'
        name = input(menu)
        type_number = type_dict[name]
        # 获取电影总数
        total = self.total_number(type_number)
        for start in range(0,(total+1),20):
           #构建查询参数
            params = {
                'type' : type_number,
                'interval_id' : '100:90',
                'action' : '',
                'start' : str(start),
                'limit' : '20'
            }
            # 调用函数,传递params参数
            self.get_page(params)
            # 随机休眠1-3秒
            time.sleep(random.randint(1,3))
        print('电影总数量:%d部'%self.i )

if __name__ == '__main__':
    spider = DoubanSpider()
    spider.main()

23、Cookie模拟登录人人网
import requests
from lxml import etree

class RenrenLogin(object):
  def __init__(self):
    # 个人主页的url地址
    self.url = 'http://www.renren.com/972496145/profile'
    self.headers = {
      # 将拷贝的cookie值放在此处
      'Cookie':'anonymid=kmol2vxqgd4n0e; depovince=HEB; _r01_=1; ick_login=c577d6c0-0ec3-465a-89d0-9e2b8f23e107; taihe_bi_sdk_uid=0738130d7f4532165841f09abc596215; taihe_bi_sdk_session=6277ea795624ba1eddb2603d7fe45c85; _de=1D29BC9596B9643C92425970B59A3DAE; p=3e6989099ff75de92407b791266376095; first_login_flag=1; ln_uact=18519784236; ln_hurl=http://hdn.xnimg.cn/photos/hdn321/20191017/0945/h_main_El46_9a13000ecbe41986.jpg; t=7f25f8a4d3515786d146143f63d108b25; societyguester=7f25f8a4d3515786d146143f63d108b25; id=972496145; xnsid=9770206d; wpsid=15900539012757; ver=7.0; loginfrom=null; wp_fold=0; jebecookies=59f8dfaf-8416-4dbc-a539-016a7ae1b6c5|||||',
      # 注意,useragent不能改变,否则cookie失效
      'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
    }

  def get_html(self):
    html = requests.get(url=self.url,headers=self.headers).text
    self.parse_html(html)

  def parse_html(self,html):
    parse_html = etree.HTML(html)
    r_school = parse_html.xpath('//*[@id="operate_area"]/div[1]/ul/li[1]/span/text()')
    print(r_school)
    r_birthday = parse_html.xpath('//li[@class="birthday"]/span/text()')
    print(r_birthday)
    home_info=parse_html.xpath('//*[@id="operate_area"]/div[1]/ul/li/text()')
    item = {}
    item['hometown'] = home_info[2].strip()
    item['address'] = home_info[3].strip()
    print(item)

if __name__ == '__main__':
  spider = RenrenLogin()
  spider.get_html()

24、多线程爬虫
# -*- coding:utf8 -*-
import requests
from threading import Thread
from queue import Queue
import time
from fake_useragent import UserAgent
from lxml import etree
import csv
from threading import Lock
import json

class XiaomiSpider(object):
  def __init__(self):
    self.url = 'http://app.mi.com/categotyAllListApi?page={}&categoryId={}&pageSize=30'
    # 存放所有URL地址的队列
    self.q = Queue()
    self.i = 0
    # 存放所有类型id的空列表
    self.id_list = []
    # 打开文件
    self.f = open('XiaomiShangcheng.csv','a',encoding='utf-8')
    self.writer = csv.writer(self.f)
    # 创建锁
    self.lock = Lock()

  def get_cateid(self):
    # 请求
    url = 'http://app.mi.com/'
    headers = { 'User-Agent': UserAgent().random}
    html = requests.get(url=url,headers=headers).text
    # 解析
    parse_html = etree.HTML(html)
    xpath_bds = '//ul[@class="category-list"]/li'
    li_list = parse_html.xpath(xpath_bds)
    for li in li_list:
      typ_name = li.xpath('./a/text()')[0]
      typ_id = li.xpath('./a/@href')[0].split('/')[-1]
      # 计算每个类型的页数
      pages = self.get_pages(typ_id)
      #往列表中添加二元组
      self.id_list.append( (typ_id,pages) )

    # 入队列
    self.url_in()

  # 获取count的值并计算页数
  def get_pages(self,typ_id):
    # 获取count的值,即app总数
    url = self.url.format(0,typ_id)
    html = requests.get(
      url=url,
      headers={'User-Agent':UserAgent().random}
    ).json()
    count = html['count']
    pages = int(count) // 30 + 1
    return pages

  # url入队函数,拼接url,并将url加入队列
  def url_in(self):
    for id in self.id_list:
      # id格式:('4',pages)
      for page in range(1,id[1]+1):
        url = self.url.format(page,id[0])
        # 把URL地址入队列
        self.q.put(url)

  # 线程事件函数: get() -请求-解析-处理数据,三步骤
  def get_data(self):
    while True:
       # 判断队列不为空则执行,否则终止
      if not self.q.empty():
        url = self.q.get()
        headers = {'User-Agent':UserAgent().random}
        html = requests.get(url=url,headers=headers)
        res_html = html.content.decode(encoding='utf-8')
        html=json.loads(res_html)
        self.parse_html(html)
      else:
        break
  # 解析函数
  def parse_html(self,html):
    # 写入到csv文件
    app_list = []

    for app in html['data']:
      # app名称 + 分类 + 详情链接
      name = app['displayName']
      link = 'http://app.mi.com/details?id=' + app['packageName']
      typ_name = app['level1CategoryName']
      # 把每一条数据放到app_list中,并通过writerows()实现多行写入
      app_list.append([name,typ_name,link])

      print(name,typ_name)
      self.i += 1

    # 向CSV文件中写入数据
    self.lock.acquire()
    self.writer.writerows(app_list)
    self.lock.release()

  # 入口函数
  def main(self):
    # URL入队列
    self.get_cateid()
    t_list = []
    # 创建多线程
    for i in range(1):
      t = Thread(target=self.get_data)
      t_list.append(t)
      # 启动线程
      t.start()

    for t in t_list:
        # 回收线程   
        t.join()

    self.f.close()
    print('数量:',self.i)

if __name__ == '__main__':
  start = time.time()
  spider = XiaomiSpider()
  spider.main()
  end = time.time()
  print('执行时间:%.1f' % (end-start))

25、bs4
pip install bs4

26、bs4爬取小说
import urllib.request
import random
from bs4 import BeautifulSoup
import time
def request_html(url):
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'}
    request = urllib.request.Request(url, headers=headers)
    return request

def parse_html(html, f):
    # 生成soup对象
    soup = BeautifulSoup(html, 'lxml')
    # 查找所有的章节链接和标题内容
    list_name = soup.select('.book-mulu > ul > li > a')
    # 遍历每一个列表中的tag对象,获取链接个目录
    for item in list_name:
        # 获取链接
        #item: <a href="/book/liangjinyanyi/1.html">自序</a>
        #拼接目录链接,此处item类型为<class 'bs4.element.Tag'>,使用下面方法可以值获取href属性值
        href = 'http://www.shicimingju.com' + item['href']
        # 获取标题
        title = item.text
        print('正在下载:-**--%s--**-......' % title)
        # 获取章节内容函数
        text = get_text(href)
        # 写入文件
        f.write(title + '\n' + text)
        print('结束下载:-**--%s--**-' % title)
        time.sleep(random.uniform(0,1))

# 提取章节内容
def get_text(href):
    #创建请求对象
    request = request_html(href)
    content = urllib.request.urlopen(request).read().decode('utf8')
    soup = BeautifulSoup(content, 'lxml')
    # 查找包含内容的tag--div
    artist = soup.find('div', class_='chapter_content')
    #获取tag标签中的文本内容
    return artist.text

def run():
    # 打开文件
    f = open('两晋演义.txt', 'w', encoding='utf8')
    url = 'http://www.shicimingju.com/book/liangjinyanyi.html'
    # 构建请求对象
    request = request_html(url)
    # 发送请求,得到响应,转换为HTML对象
    html = urllib.request.urlopen(request).read().decode('utf8')
    # 解析内容
    parse_html(html,f)
    #关闭文件
    f.close()

if __name__ == '__main__':
    run()


posted on 2022-06-21 01:04  突破%  阅读(58)  评论(0)    收藏  举报

导航