【0基础】纵横中文网python爬虫实战

原文在此:【0基础】纵横中文网python爬虫实战

大家好,我是你们的机房老哥!

在粉丝群的日常交流中,爬虫是比较常见的话题。python最强大的功能之一也是爬虫。

考虑到很多0基础的小白想要入门爬虫。老哥今天就通过一个比较简单的爬虫,介绍一下python爬虫的流程及思路,并扫盲爬虫常用工具的语法。

本次教程您将学到:

爬虫思路、流程

xpath全解析

css选择器全解析

requests_html库进阶

▲最终成果

话不多说,接下来就是:

-STUDY PYTHON WITH-

基础教程——纵横中文python爬虫

-OLDER BROTHER-

获取小说信息

http://book.zongheng.com/store.html

▲纵横中文网

要爬取的网址如上图所示。

导入老哥最常用的爬虫库requests_html库,首先将HTMLSession()函数定义为session。使用session.get()命令提交响应,最后打印r.html.html查看网页源代码。

```

from requests_html import HTMLSession

session = HTMLSession()

url = 'http://book.zongheng.com/store.html'

r = session.get(url)print(r.html.html)

```

▲打印网页源码

如上图所示,老哥已经成功获得网页源码了。说明网站的反爬手段比较弱,适合新手练习。

▲分析网址结构

按F12打开控制台,可以看到左侧小说的信息在<div class="bookbox fl" </div>下,右侧小说的信息在<div class="bookbox fr" </div>下。网址结构非常简单。

▲分析小说名称

我们点入每个小说信息的div下,获取小说的信息。

可以看到,<div  class="bookname">标签下的a标签中,href是小说网址,内容是小说标题。

<div  class="booklink">标签下的第一个a标签中,href是作者的介绍页网址,内容是作者笔名。第二个a标签中,href是小说分类主题页网址,内容是小说分类。第一个span中是小说连载状态,第二个span中是小说更新时间。

接下来通过xpath分别提取这些信息,代码如下:

```

bookname = r.html.xpath('//div[@class="bookname"]/a/text()')

bookname_links = r.html.xpath('//div[@class="bookname"]/a/@href')

authorname = r.html.xpath('//div[@class="bookilnk"]/a/text()')

author_links = r.html.xpath('//div[@class="bookilnk"]/a/@href')

typename = r.html.xpath('//div[@class="bookilnk"]/a[2]/text()')

type_links = r.html.xpath('//div[@class="bookilnk"]/a[2]/@href')

status = r.html.xpath('//div[@class="bookilnk"]/span/text()')

time_ = r.html.xpath('//div[@class="bookilnk"]/span[2]/text()')

for num in range(len(bookname_links)):

    print(bookname[num], bookname_links[num], authorname[num], author_links[num], typename[num], type_links[num],

          status[num].strip(), time_[num].strip())

```

解析上述代码:通过r.html.xpath调用库中自带的xpath语法提取小说名。//div代表任意位置的div标签,[@class="bookname"]是xpath语法,中括号中@符号后是div的属性,这里用div的标签class="bookname"定位到小说名称。/a代表这个div下的第一个a标签,最后用text()函数提取a标签内容,即小说标题。

提取网址方法类似,区别在于在a标签后接/@href提取a标签下的href属性。

当一个div标签下有两个a标签时,a[2]代表第二个a标签。

▲获取小说信息

这里顺便扫盲一下xpath的基础语法:

详解xpath

选取节点:

xpath('/div')——从根节点上选取div节点。

xpath('//div')——选取所有div节点。

xpath('./div')——选取当前节点下的div节点。

xpath('../a')——选取当前的父节点下的第一个a节点。

谓语:

xpath('/body/div[1]') ——选取body下的第一个div节点。

xpath('/body/div[last()]')——选取body下的最后一个div节点。

xpath('/body/div[last()-1]')——选取body下的倒数第2个div节点。

xpath('/body/div[positon()<3]')——选取body下的前2个div节点。

xpath('/body/div[@class]')——选取body下带有class属性的div节点。

xpath('/body/div[@class="main"]')——选取body下class属性为main的div节点。

xpath('/body/div[price>35.00]')——选取body下price元素值大于35的div节点。

xpath('/div/*')——选取div下的所有子节点。

xpath('/div[@*]')——选取所有带属性的div节点。

xpath('/div/node()')——匹配div下任何类型的节点。

xpath('//div|//table')——选择所有div和table节点。

功能函数:

xpath('//div[starts-with(@id,"ma")]')——选取id值以ma开头的div节点。

xpath('//div[contains(@id,"ma")]')——选取id值包含ma的div节点。

xpath('//div[contains(@id,"ma") and contains(@id,"in")]')——选取id值包含ma和in的div节点。

xpath('//div[contains(text(),"ma")]')——选取文本中包含ma的节点。

在这里老哥在稍微拓展一下。获得小说链接,除了上文中的方式,还可以用如下代码:

bookname_links = r.html.xpath('//div[@class="bookname"]/a', first=True)

print(bookname_links.attrs['href'])

解析一下上述代码,使用first=True提取div下的第一个a标签。在这里用.attrs['href']命令提取a标签下的href属性,同样可以得到链接。

值得注意的是,first=True提取的是第一个标签,返回element格式。如果不加,则返回列表格式,就不能使用该方法了。

▲方法2获得href下的链接  

进入小说内容页

上文中已经提取到小说的链接,我们只需要再次用session.get()命令请求这个链接,即可得到小说内容。

▲小说详情页

不过,上文中提出的链接点进去是小说详情页,所以想要获取小说内容,还需要提取“开始阅读”对应的href链接。代码如下:

```

bookname_links = r.html.xpath('//div[@class="bookname"]/a/@href')

for num in range(len(bookname_links)):

    bookname_link = bookname_links[num]

    r = session.get(bookname_link)

    r2 = r.html.xpath('//div[contains(@class,"btn-group")]/child::a')[0].links

    print(r2)

```

解析上述代码:老哥为了拓展教程,用了第三种方式提取链接。首先解析xpath语法,//div[contains(@class,"btn-group")],代表获取包含"btn-group"的class属性的div节点。这种方式的好处在于,假如该div节点的class有很多,写起来比较复杂,就可以用contains获取该class中包含的某个唯一字段。/child::a代表该div下的第一个子节点a。

由于这种方式得到的是一个列表,提取列表的第一个值,该值包含小说链接。这个值是<class

'requests_html.Element'>类型,这种类型是requests_html库自带的类型,可以使用.links命令提取该requests_html.Element下的所有链接。因为本案例只有一个链接,所以就返回一个值,即小说的链接。

上述代码中的r2即小说内容页的链接。

进阶:requests_html的.links命令

为了更好的理解.links命令的强大之处,老哥附带一个小案例。例如用.links命令提取根网站下的所有网址,代码如下:

```

from requests_html import HTMLSession

session = HTMLSession()

url = 'http://book.zongheng.com/store.html'

r = session.get(url)

print(r.html.links)

```

▲轻松获取所有链接

可以看到,如果请求的网址下有很多网址,用.links命令可以不费吹灰之力的得到他们。

有时一些链接只有后半部分,需要拼接网站的域名才能使用,这时候,只需要将.links改成.absolute_links,即可获得自动补全的所有链接。

小说内容提取

最后一步就是小说内容提取,方法和上文类似,就不赘述了。这个网站有趣的地方在于禁止左键、右键点击。如果不会爬虫,只会复制粘贴网页信息的话,就会被难住了。当然用爬虫就完全无视这种“小伎俩”啦。

▲小说内容

这部分和上文类似,解析标题、内容所在位置,为了拓展教程,老哥这里使用css选择器。代码如下:

```

r3 = session.get(list(r2)[0])

title = r3.html.find('.title_txtbox', first=True).text

author = r3.html.find('.bookinfo', first=True).text

content = r3.html.find('.content', first=True).text

```

解析上述代码,r3.html.find()代表使用css选择器。.title_txtbox代表选择class为title_txtbox的值,.是css选择器中选择class类型的符号。最后用.text命令获取内容,类似.links命令。

扫盲一下css选择器的基础语法:

详解CSS选择器

.intro——选择class="intro"的所有元素。 

#firstname——选择id="firstname"的所有元素。 

*——选择所有元素。 

p——选择所有<p>元素。 

div,p——选择所有<div>元素和所有<p>元素。 

divp——选择<div>元素内部的所有<p>元素。 

div>p——选择父元素为<div>元素的所有<p>元素。 

div+p——选择紧接在<div>元素之后的所有<p>元素。 

[target]——选择带有target属性所有元素。 

[target=_blank]——选择target="_blank"的所有元素。 

[title~=flower]——选择title属性包含单词"flower"的所有元素。 

[lang|=en]——选择lang属性值以"en"开头的所有元素。 

a:link——选择所有未被访问的链接。 

a:visited——选择所有已被访问的链接。 

a:active——选择活动链接。 

a:hover——选择鼠标指针位于其上的链接。 

input:focus——选择获得焦点的input元素。 

p:first-letter——选择每个<p>元素的首字母。 

p:first-line——选择每个<p>元素的首行。 

p:first-child——选择属于父元素的第一个子元素的每个<p>元素。 

p:before——在每个<p>元素的内容之前插入内容。 

p:after——在每个<p>元素的内容之后插入内容。 

p:lang(it)——选择带有以"it"开头的lang属性值的每个<p>元素。 

p~ul——选择前面有<p>元素的每个<ul>元素。 

a[src^="https"]——选择其src属性值以"https"开头的每个<a>元素。 

a[src$=".pdf"]——选择其src属性以".pdf"结尾的所有<a>元素。 

a[src*="abc"]——选择其src属性中包含"abc"子串的每个<a>元素。 

p:first-of-type——选择属于其父元素的首个<p>元素的每个<p>元素。 

p:last-of-type——选择属于其父元素的最后<p>元素的每个<p>元素。 

p:only-of-type——选择属于其父元素唯一的<p>元素的每个<p>元素。 

p:only-child——选择属于其父元素的唯一子元素的每个<p>元素。 

p:nth-child(2)——选择属于其父元素的第二个子元素的每个<p>元素。 

p:nth-last-child(2)——同上,从最后一个子元素开始计数。 

p:nth-of-type(2)——选择属于其父元素第二个<p>元素的每个<p>元素。 

p:nth-last-of-type(2)——同上,但是从最后一个子元素开始计数。 

p:last-child——选择属于其父元素最后一个子元素每个<p>元素。 

:root——选择文档的根元素。 

p:empty——选择没有子元素的每个<p>元素(包括文本节点)。 

#news:target——选择当前活动的#news元素。 

input:enabled——选择每个启用的<input>元素。 

input:disabled——选择每个禁用的<input>元素   

input:checked——选择每个被选中的<input>元素。 

:not(p)——选择非<p>元素的每个元素。 

::selection——选择被用户选取的元素部分。   

翻页

▲翻页

这里涉及到翻页,因为小说只有下一页,没有具体页数,所以只能循环读取下一页来不停的获取小说内容。

```

nextchapter = list(r3.html.find('.nextchapter', first=True).links)[0]

```

获取到下一页网址后,写一个循环来获取下一页,直到无法获取,则爬取完一本小说的所有内容。

```

for i in range(100000):

    try:

        name = session.get(nextchapter)

        title = name.html.find('.title_txtbox', first=True).text

        author = name.html.find('.bookinfo', first=True).text

        content = name.html.find('.content', first=True).text

        nextchapter = list(name.html.find('.nextchapter', first=True).links)[0]

        print(title,'\n', content)

    except:

        break

```

解析上述代码,设定一个极大的值,让程序不断循环,获取每页的小说,直到最后一页,无法获取小说内容时,break跳出循环,并开启一本新的小说的爬取。

欣赏一下最终的成果吧!

这样一个基础爬虫教程就结束了,是不是很简单呢!

本次教程的源代码,在公众号后台回复“小说爬虫”即可获取

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容