python爬虫笔记

混江龙づ霸主 提交于 2020-03-23 10:17:18
##爬虫    -通用网络爬虫        其的主要目的是将互联网上的资源下载到本地形成一个镜像备份。类似百度等搜索引擎        -聚焦爬虫        其面向特定需求的爬虫程序,与通用爬虫的区别在于对数据进行筛选尽量爬取相关数据        -爬虫优化        1.尽量减少请求次数        2.web页面不好爬取时爬app和h5页面(手机)            ##HTTP和HTTPS    --超文本传输协议    HTTP 端口80    HTTPS时加入了ssl安全传输协议   端口443        ##get请求方式获取    ---get方式一般用于向服务器获取数据     --parse用于url编码        实际使用是将url地址与想要查询的数据信息拼接形成完整地url        例如        # https://tieba.baidu.com/f?ie=utf-8&kw=火影忍者&fr=search           # https://tieba.baidu.com/f?kw=火影忍者&ie=utf-8&pn=50             base_url = 'http://wwww.baidu.com/f?'        # 搜索信息关键字        wd = input('搜索信息关键字')        pn = input('pn值')        q_data = {            'wd' = wd,            'pn' = pn,        }         # 对q_data进行编码使用parse模块        q_data = parse.urlencode(q_data)        # 拼接url        full_url = base_url + q_data        # 构造请求对象        req = request.Request(url=full_url,headers=headers)        # 获取响应对象        response = request.urlopen(req).read().decode('utf-8')                ##post请求方式    --post方式需要向服务器发送一些数据        需要注意的是post传数据时不仅要使用parse转码还需要将其转化为字节形式        例如:                base_url = 'http://wwww.baidu.com/'                headers = {                    'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0",                }                # post携带数据                kw = input(">>")                data = {                    'kw': kw                }                parse_data = parse.urlencode(data)                            req = request.Request(url=base_url,data=bytes(data,encoding='utf-8'),headers=headers)                response = request.urlopen(req).read().decode('utf-8')        ##cookies    --获取cookies        cookies_object = cookiejar.CookieJar()        cookies_handler = request.HTTPCookieProcessor(cookies_object)        http_handler = request.HTTPHandler()        https_handler = request.HTTPSHandler()        opener = request.build_opener(http_handler,https_handler,cookies_handler)##ssl    ---免认证        # 忽略未经核实的ssl证书认证        ssl._create_default_https_context = ssl._create_unverified_context()    ##登录网页爬取开心网    ---登录url        https://security.kaixin001.com/login/login_post.php        邮箱:loginemail        密码:password##有道翻译    '''    分析:    爬取步骤          1 获取url        2 data数据填写 headers数据填写        3 构造request对象生成响应    data中的数据{                i  "job"                from   "AUTO"                to "AUTO"                smartresult    "dict"                client "fanyideskweb"                salt   "15842516730329"                sign   "60f53618f3fa667e6d3192148c8c1a03"                ts "1584251673032"                bv "e2a78ed30c66e16a857c5b6486a1d326"                doctype    "json"                version    "2.1"                keyfrom    "fanyi.web"                action "FY_BY_REALTlME"    }      headers中的数据{                Host: fanyi.youdao.com                User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0                Accept: application/json, text/javascript, */*; q=0.01                Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2                Accept-Encoding: gzip, deflate  # 此行使用时需要注释掉 不要接受压缩信息文件                Content-Type: application/x-www-form-urlencoded; charset=UTF-8                X-Requested-With: XMLHttpRequest                Content-Length: 236                 Origin: http://fanyi.youdao.com                Connection: keep-alive                Referer: http://fanyi.youdao.com/                # 我写代码时cookie有问题换了别人的cookie值可以正常爬取而我的会生成{‘errorcode’:50}错误                Cookie: OUTFOX_SEARCH_USER_ID=-140868279@123.121.59.79; OUTFOX_SEARCH_USER_ID_NCOO=1766192849.313334; _ntes_nnid=700fcdc75a16b68417175b615d961ea3,1537510225088; YOUDAO_MOBILE_ACCESS_TYPE=1; JSESSIONID=aaa_XsoMzWSA17Bi3OCdx; ___rl__test__cookies=1584251673023    }      难点        因为是post方式提交的数据所以在浏览器调试模式中查找请求方式为post的进行查看        post提交数据中i 为查询的数据   salt、sign和ts    会发生变化        获取salt和sign 的加密方式   在   fanyi.min.js    文件中使用代码格式化工具https://tool.oschina.net/codeformat/js 查找salt与sign关键字        salt: i    i = r + parseInt(10 * Math.random(), 10);        sign:  n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")        ts:r       r = "" + (new Date).getTime(),    '''        ##豆瓣电影分类排行    分析    爬取步骤        1.获取url信息        2.数据爬取        3.数据保存                页面分析一次显示20条信息        json数据中的请求url显示为:         https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=0&limit=20        https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=20&limit=20        https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=40&limit=20        start 为起始点        limit 为显示信息        type 为剧情类型                难点:            需要爬取所有类型的type_id            response = requests.get(url=url, headers=headers)            douban_html = etree.HTML(response.text)            datas = douban_html.xpath("//div[@class='article']/div[2]/div[@class='types']/span")                    for href in datas:                info = href.xpath(".//@href")[0].split('&')[1]                name = href.xpath(".//a")[0].text                movies_type[name] = info##代理ip        # ProxyHandler代理ip        # 免费短期代理网站举例:        # 西刺免费代理 IP:http://www.xicidaili.com/        # 快代理免费代理:https://www.kuaidaili.com/free/inha/        # 全网代理 IP:http://www.goubanjia.com/        '''            urllib中的request模块            1.定义代理对象            2.创建opener对象使用代理            3.构造请求对象            4.发送请求                '''        from urllib import request        import random        # 单个代理ip        # proxy_ = request.ProxyHandler({        #     # 代理ip        #     "http":'122.224.65.198:3128',        # })                # 多个ip代理使用  也可以从文件中读取        proxy_list = [            {"http":'122.224.65.198:3128'},            {"http":'111.160.169.54:42626'},            {"http":'116.196.87.86:20183'},            {"http":'123.58.17.134:3128'},        ]        proxy_ = random.choice(proxy_list)                # 生成代理对象        proxy_handler = request.ProxyHandler(proxy_)                opener = request.build_opener(proxy_handler)                # 构造请求        req = request.Request(url='http://wwww.baidu.com/')        # 发送请求        response = opener.open(req)                ##西刺代理ip爬取    ##request模块使用   ####get方式        # 导入模块        import requests        # get 无参        response = requests.get('url')        # 还可以用request 方法request("请求方法",'url')        response = requests.request("get",'url')        # get 带参数 params参数接收字典或字符串        response = requests.get('url',params=dict1{},headers=headers)  ####post方式         # 导入模块        import requests        # data = {        #     # 提交数据        # }        # response = requests.request("post",url='',data=data,headers=headers)          #### ip代理        # proxies 参数    公开代理ip        # proxies = [        #     {"http": '122.224.65.198:3128'},        #     {"http": '111.160.169.54:42626'},        #     {"http": '116.196.87.86:20183'},        #     {"http": '123.58.17.134:3128'},        # ]        # response = requests.request('get',url='',params=dict1,headers=headers,proxies=proxies)                # proxies 参数使用  私密代理        # proxy = {"http":"用户名:密码@ipd地址:端口"}        # response = requests.request('get',url='',params=dict1,headers=headers,proxies=proxy)             #### 获取数据后        response.text   # 返回Unicode格式数据        response.content # 返回字节流数据用于保存二进制数据        response.json   # 返回json文件        response.url  # 返回完整url        response.encoding   # 返回响应编码格式        response.status_code    # 返回响应码                ##cookies和session        # cookies_obj = response.cookies    # 获取cookies对象        # cookies_dict = response.utils.dict_from_cookiejar(cookies_obj)    # 将cookies转换为字典        '''        session 对象获取cookies保存以便访问登录之后的页面        '''        # 生成session对象        session_obj = requests.session()        # 发送post请求登录页面        form_data = {            'email':'',            'password':'',        }        session_obj.post(url='',data=form_data)        # 此时cookies存储在session_obj中可以利用session_obj直接访问页面        response = session_obj.get(url='')##全国邮编爬取     设置解码格式防止出现乱码    response.encoding = 'gb2312'    '''    https://www.ip138.com/post/    https://www.ip138.com/10/   北京邮编url    //table/tbody/tr[2] 北京邮编xpath    '''        ##scrapy安装    -选择相应按本的twisted        进入https://www.lfd.uci.edu/~gohlke/pythonlibs/,下载对应的whl文件。cp后面是python版本,amd64代表64位win32代表32位        命令:        pip install C:\Users\Administrator\Desktop\Twisted-19.10.0-cp38-cp38-win32.whl安装scrapy        pip  install  -i  https://pypi.doubanio.com/simple/  --trusted-host pypi.doubanio.com scrapy    -建立项目        命令行输入:        scrapy startproject 项目名    -scrapy框架结构与工作原理        引擎,调度器,下载器,爬虫,数据管道,中间件        spider发现URL生成request对提交给引擎随后进入调度器排队,之后进入下载器,下载器根据request对象的URL发送HTTP请求返回一个response对象        发送给spider的解析函数处理,将提取的数据封装成item提交给引擎,然后交给数据管道处理,其中若页面中有URL则重复以上步骤##框架解析    scrapy.cfg :项目的配置文件     mySpider/ :项目的 Python 模块,将会从这里引用代码    mySpider/items.py :项目的目标文件      mySpider/pipelines.py :项目的管道文件     mySpider/settings.py :项目的设置文件     mySpider/spiders/ :存储爬虫代码目录 ##items    Item 定义结构化数据字段,用来保存爬取到的数据。明确存储信息。    可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个 Item(可以理解成类似于 ORM 的映射关系)。    例子:    class MeiJuItem(scrapy.Item):        '''爬取美剧        定义MeiJuItem类继承scrapy.Item定义存储数据        '''        name = scrapy.Field()        href = scrapy.Field()        state = scrapy.Field()        tv = scrapy.Field()        time = scrapy.Field()##spider           -爬虫编写        步骤        1.导入scrapy库和相应item类        2.继承scrapy的spider类        3.name 用于唯一标识spider start_urls 用于存放需要爬取的URL             4.重写页面解析函数parse    -parse方法        1.提取页面数据        2.提出新的页面请求    例子:    import scrapy    from example.items import  MeiJuItem    class MeiJuSpider(scrapy.Spider):        name = 'meiju'        start_urls = ["https://www.meijutt.tv/new100.html"]        def parse(self, response):            page_data = response.xpath(".//ul[@class='top-list  fn-clear']/li")            for li_data in page_data:                item = MeiJuItem()                item['name'] = li_data.xpath("./h5/a/@title").extract()[0]                item['href'] = li_data.xpath("./h5/a/@href").extract()[0]                item['state'] = li_data.xpath("./span[@class='state1 new100state1']/string()").extract()[0]                item['tv'] = li_data.xpath("./span[@class='mjtv']/text()").extract()[0]                item['time'] = li_data.xpath("./div[@class='lasted-time new100time fn-right']/text()").extract()[0]                yield item##item pipeline以下是Item Pipeline的几种典型应用:     ● 清洗数据。     ● 验证数据的有效性。     ● 过滤掉重复的数据。     ● 将数据存入数据库。    ● open_spider(self, spider) Spider打开时(处理数据前)回调该方法,        通常该方法用于 在开始处理数据之前完成某些初始化工作,如连接数据库。     ● close_spider(self, spider) Spider关闭时(处理数据后)回调该方法,        通常该方法用于 在处理完所有数据之后完成某些清理工作,如关闭数据库。     ● from_crawler(cls, crawler) 创建Item Pipeline对象时回调该类方法。        通常,在该方法中通过crawler.settings读取配置,根据配置创建Item Pipeline对象。    编写 item pipeline 很简单,item pipiline 组件是一个独立的 Python 类,其中 process_item() 方法必须实现    例子    class MeiJuPipeline(object):    def __init__(self):        # 可选实现,做参数初始化等        self.file = open('meiju.json','wb')        pass    def process_item(self,item,spider):        '''        # item (Item 对象) – 被爬取的 item        # spider (Spider 对象) – 爬取该 item 的 spider        # 这个方法必须实现,每个 item pipeline 组件都需要调用该方法,        # 这个方法必须返回一个 Item 对象,被丢弃的 item 将不会被之后的 pipeline 组件 所处理。        '''        json.doump(dict(item),open('meiju.json','a',encoding='utf-8'),ensure_ascii=False)        return item        pass    def open_spider(self, spider):        # spider (Spider 对象) – 被开启的 spider        # 可选实现,当 spider 被开启时,这个方法被调用。        pass    def close_spider(self,spider):        # spider (Spider 对象) – 被关闭的 spider        # 可选实现,当 spider 被关闭时,这个方法被调用        self.file.close()##log在setting中配置    LOG_FILE = "meiju.log"     LOG_LEVEL = "INFO"    ##middlewares中间键    DOWNLOADER_MIDDLEWARES = { 'scrapy_crawlera.CrawleraMiddleware': 600 }代理    Scrapy 代理 IP、Uesr-Agent 的切换都是通过 DOWNLOADER_MIDDLEWARES 进行控制        CRAWLERA_ENABLED = True         CRAWLERA_USER = '注册/购买的         UserKey' CRAWLERA_PASS = '注册/购买的 Password 或者    修改 settings.py 配置 USER_AGENTS 和 PROXIES    USER_AGENTS = [ "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",                     "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0;                    ]    PROXIES = [         {'ip_port': '111.8.60.9:8123', 'user_passwd': 'user1:pass1'},         {'ip_port': '101.71.27.120:80', 'user_passwd': 'user2:pass2'},         {'ip_port': '122.96.59.104:80', 'user_passwd': 'user3:pass3'},         {'ip_port': '122.224.249.122:8088', 'user_passwd': 'user4:pass4'}     ]下载延迟settings文件中配置    DOWNLOAD_DELAY = 3例子:    import random     import base64    from settings import USER_AGENTS     from settings import PROXIES     # 随机的 User-Agent     class RandomUserAgent(object):         def process_request(self, request, spider):             useragent = random.choice(USER_AGENTS)             request.headers.setdefault("User-Agent", useragent)     class RandomProxy(object):         def process_request(self, request, spider):             proxy = random.choice(PROXIES)             if proxy['user_passwd'] is None:             # 没有代理账户验证的代理使用方式                 request.meta['proxy'] = "http://" + proxy['ip_port']             else:             # 对账户密码进行 base64 编码转换                 base64_userpasswd = base64.b64encode(proxy['user_passwd'])                 # 对应到代理服务器的信令格式里                 request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd                 request.meta['proxy'] = "http://" + proxy['ip_port']       ##settings在 scrapy 当中,可以在 scrapy.Request 中加入 dont_filter=False(默认去重)###xpath在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。    XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。    --节点关系        --父节点            每个元素以及属性都有一个父。            在例子中book 元素是 title、author、year 以及 price 元素的父        --子节点            元素节点可有零个、一个或多个子。            在例子中title、author、year 以及 price 元素都是 book 元素的子        --同级节点            拥有相同的父的节点            在下面的例子中,title、author、year 以及 price 元素都是同级节点          -例子            <book>              <title>Harry Potter</title>              <author>J K. Rowling</author>              <year>2005</year>              <price>29.99</price>            </book>     --xpath语法        XPath 使用路径表达式在 XML 文档中选取节点。        nodename   选取此节点的所有子节点。        /          从根节点选取。        //             从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。        .          选取当前节点。        ..             选取当前节点的父节点。        @          选取属性。    --例子        bookstore  选取 bookstore 元素的所有子节点。        /bookstore     选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!        bookstore/book     选取属于 bookstore 的子元素的所有 book 元素。        //book     选取所有 book 子元素,而不管它们在文档中的位置。        bookstore//book    选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。        //@lang    选取名为 lang 的所有属性。    --复杂例子        /bookstore/book[1]     选取属于 bookstore 子元素的第一个 book 元素。        /bookstore/book[last()]    选取属于 bookstore 子元素的最后一个 book 元素。        /bookstore/book[last()-1]  选取属于 bookstore 子元素的倒数第二个 book 元素。        /bookstore/book[position()<3]  选取最前面的两个属于 bookstore 元素的子元素的 book 元素。        //title[@lang]     选取所有拥有名为 lang 的属性的 title 元素。        //title[@lang='eng']   选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。        /bookstore/book[price>35.00]   选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。        /bookstore/book[price>35.00]//title    选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。    --xpath使用        导入lxml中的etree模块        使用etree的HTML方法将页面信息转化为xml文档        此时可以使用xml对象进行xpath数据提取###bs4    ---bs4自带转码功能不需要转码操作,其将HTML转换为树形结构    ---tag 对应 标签 使用 对象名.标签名  返回第一个满足条件的标签        name    name属性获取标签名称        例如:            name = soup.img.name        attrs   attrs属性获取标签的属性生成字典        例如:            img = soup.img.attrs            src = img.get("src")        string  string属性获取标签中的文本        例如:            text = soup.title.string        contents    contents属性获取直接子节点返回一个列表        children    children属性返回一个生成器    ---文档树搜索        find__all(name,attrs,recursive,text,**kwargs)        name    --标签名称            ----参数                字符串          -直接查询标签                正则表达式      -查询满足正则的所有标签                列表            -查询和列表中匹配的标签        attrs   --标签属性             ----参数                属性名=值       -查询满足条件的标签        text    --标签内容            ----参数和name一样接收字符串、正则表达式、列表        css选择器        类名前加 .  id名前加 # 标签名不加修饰        select()    返回结果为列表        标签名查找   soup.select(标签名)     例如: soup.select('title')类名查找     soup.select('.类名')    例如: soup.select('.input')        id名查找     soup.select('#id名')    例如: soup.select('#head_wrapper')组合查找     soup.select('div .input')                     soup.select('div #head_wrapper')属性查找     soup.select('div img[class="weixin"]')内容获取    使用get_text()方法      ---scrapy中        -标签提取            response.css('title')获取到一个selector列表例如:            [<Selector xpath='descendant-or-self::title' data='<title>百度一下,你就知道</title>'>]        -extract方法获取到标签列表            ['<title>百度一下,你就知道</title>']        -extract_first方法获取到标签            '<title>百度一下,你就知道</title>'        -::text 获取到标签中的数据            response.css('title::text').extract_first()            ---- response.css('标签名::text').extract_first()        -class选择器             即<div class="quote post">中的class            info.css('.text::text').extract_first()对象.css('标签.class名称::text').extract_first()        -ID选择器             即<div id="quote">中的id            info.css('#quote::text').extract_first()对象.css('标签#id名称::text').extract_first()       ---    1.导入模块    from bs4 import BeautifulSoup    2.生成对象    soup=BeautifulSoup(html文档,'lxml')    3.格式化输出对象内容    content= soup.prettify()##re    match 方法:从起始位置开始查找,一次匹配     search 方法:从任何位置开始查找,一次匹配    findall 方法:全部匹配,返回列表     finditer 方法:全部匹配,返回迭代器     split 方法:分割字符串,返回列表     sub 方法:替换        ^  匹配字符串的开头    $  匹配字符串的末尾。    .  匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。    [...]  用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'    [^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符     \w 匹配数字字母下划线    \W 匹配非数字字母下划线    \s 匹配任意空白字符,等价于 [\t\n\r\f]。    \S 匹配任意非空字符    \d 匹配任意数字,等价于 [0-9]。    \D 匹配任意非数字    *  匹配0个或多个的表达式。    +  匹配1个或多个的表达式。    ?  匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式`##json模块用于对json类型与python类型相互转换    loads json.loads("json字符串")    dumps   json.dumps("python字符串")    dump    json.dump()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!