有关使用python爬虫的一些心得

爬虫的一些案例

相信大家使用爬虫时,都是一股脑跑进网上查询别人的代码。然后照搬网上的,发现运行的时候并没有很好地符合自己的预期。

现在我来给大家指出爬虫的基本流程,如果有错误,还望大家指正。

爬虫流程:

  1. 首先先分析需要爬取的网站,有些网站是有robot.txt,不允许哪些爬取,允许爬取哪些内容,爬取一个网站首先得注意一下这个内容,保证自己爬取的行为不会对别人的网站造成不可避免的伤害。
  2. 然后应该分析自己要爬取的内容,分析基本流程。有些网站刚进入时他的主页时,会要求你登录,不然不会给进入和爬取。
  3. 制定一个爬取的流程,例如一个url (网站的初始页面),大多数是可以直接通过url进入的,但是有些网站会通过检查你的cookie来判断你有没有登录,会强制你到登录页面。
  4. 如何得到你想要爬取的url,首先你应该进入到该网站,使用浏览器的网络分析工具,鼠标右键点击检查或者键盘上的F12,这样就可以分析所要爬取的页面了。

现在来列举一些python使用的包。

  1. 用于请求网页的python自带的urllib,requests
  2. 用于分析网页页面的BeautifulSoup,lxml(复杂操作推荐lxml)
  3. 爬取和下载可以直接使用python的open函数,对于文本或者视频不过是是否选取二进制写人模式
  4. 还有一些模仿浏览器登录的selenium,对于一些动态页面的爬取比较有效。

现在列出我写的一个爬取实例:

这份代码能1到的事情:

  1. 反鉴别,因为你的header默认是一个python爬虫的,一些网站看到这样的表头直接忽略,并且过多的请求,也会临时封禁你的ip地址,代码中会在每次请求访问一个页面,会换一个表头,无法让对方鉴别出来。
  2. 保持像个人样,不要请求过快,代码中的一些时间设置是为了更好模仿人的行为
  3. 如果爬取过多,需要你跟网站保持一个会话状态,使用requests中的session很好的与网站保持,因为你每次使用get,而没有保持会话,这样get再次使用的ip地址,而这个ip地址持续地浪费服务器的资源,肯定会把这个ip地址封禁的,如果你使用的ip被封禁了,只要断开你连的wifi(例如局域网这种),会重新分配一个ip地址给你。
  4. 使用selenium模仿浏览器,因为我要爬取的网站有javascript动态显示,所以获取它的索引会比较麻烦一点,使用selenium模仿谷歌浏览器登录,然后爬取其中的url.
python 复制代码
import requests
from lxml import etree
import random
import time
import os
from selenium import webdriver
from selenium.webdriver.common.by import By

max_entries = 3

user_agent_list = [
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/61.0",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36"
]

headers = {"User-Agent": random.choice(user_agent_list),
           "Accept-Language":"zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;",
           "Accept-Encoding":"gzip,deflate,br,zstd"
           }
parser =etree.HTMLParser(encoding="utf-8")
session = requests.Session()

options = webdriver.ChromeOptions()
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(10)

def get_novel_list(url):
    global driver
    novel_chapters = {}

    try:
        driver.get(url)
    except requests.exceptions.ConnectionError as e:
        print("Connect aborted")
    nameElems = driver.find_elements(By.XPATH,'//div[@class="direList font14 chapter_list"]/ul/li/div[@class="name"]/a')
    for nameElem in nameElems:
        name = nameElem.text
        href = nameElem.get_attribute("href")
        if name and href:
            novel_chapters[name]=href

    nextPage = driver.find_element(By.CLASS_NAME,'next')
    nextPage.click()

    time.sleep(5)

    nameElems = driver.find_elements(By.XPATH,'//div[@class="direList font14 chapter_list"]/ul/li/div[@class="name"]/a')
    for nameElem in nameElems:
        name = nameElem.text
        href = nameElem.get_attribute("href")
        if name and href:
            novel_chapters[name]=href

    driver.quit()
    return novel_chapters

def get_novel_content(novelList):
    global baseUrl
    global headers
    global parser
    global dirs
    global max_entries
    novelListChapter = {}
    for name, url in novelList.items():
        novelListChapter[name] = []
        print(f'Downloading {name}:{url}......')
        novelListChapter[name].append(url)
        try:
            headers["User-Agent"]= random.choice(user_agent_list)
            html = session.get(url,headers=headers,timeout=60)
            time.sleep(random.uniform(3,12))
        except requests.exceptions.ConnectionError as e:
            print("Connection aborted")
        tree = etree.HTML(html.content,parser=parser)
        chapterName = dirs+"/"+name+".txt"
        with open(chapterName,"w") as f:
            while True:
                texts = tree.xpath('//div[@class="content font18"]/p/text()')
                for text in texts:
                    f.write(text+'\n')
                NextUrl = tree.xpath('//div[@class="btnW font14"]/a[last()]/@href')[0]
                absoluteUrl = baseUrl + NextUrl
                if(url[:12] != NextUrl[:12]):
                    break
                for i in range(max_entries):
                    try:
                        headers["User-Agent"]= random.choice(user_agent_list)
                        html = session.get(absoluteUrl,headers=headers,timeout=60)
                        time.sleep(random.uniform(3,12))
                    except requests.exceptions.ConnectionError as e:
                        print("Connection aborted")
                    else:
                        tree = etree.HTML(html.content,parser=parser)
                        break


if __name__ == "__main__":
    baseUrl = "https://www.qianbixiaoshuo.com"
    novelUrl = "/book/0D4D.html"
    dirs = "狂神小说"
    if not os.path.exists(dirs):
        os.makedirs(dirs)
    Url = baseUrl + novelUrl
    NovelList = get_novel_list(Url)
    get_novel_content(NovelList)